Skip to content

Commit 4f14d2c

Browse files
committed
ci: require version and reason for dependency overrides
1 parent 5b33b73 commit 4f14d2c

7 files changed

Lines changed: 49 additions & 38 deletions

File tree

ci/README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,21 +116,27 @@ and npm `gitHead` when available.
116116

117117
## Overrides
118118

119-
Some profile selections can include an optional `overrides` object:
119+
Some profile selections can include an optional `overrides` object. Each entry
120+
maps a package name to a `version` and a `reason` explaining why the override
121+
exists:
120122

121123
```json
122124
{
123125
"strategy": "git_tag",
124126
"tag": "synapse-sdk-v1.0.1",
125127
"overrides": {
126-
"nanoid": "3.3.13"
128+
"nanoid": {
129+
"version": "3.3.13",
130+
"reason": "nanoid 5.x is ESM-only and breaks the CJS build"
131+
}
127132
}
128133
}
129134
```
130135

131-
Overrides are explicit profile policy. The resolver validates that this is a
132-
string-to-string map and copies it into resolved metadata. It does not infer
133-
overrides from package metadata.
136+
Overrides are explicit profile policy. Both `version` and `reason` are required
137+
non-empty strings; the resolver rejects any override missing either field, so an
138+
override cannot be added without documenting why. The reason is logged when the
139+
override is applied. The resolver does not infer overrides from package metadata.
134140

135141
Overrides are currently allowed only for:
136142

scenarios/dependencies.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ def format_markdown_table(metadata: dict | None = None) -> str:
7979
overrides = value.get("overrides") or {}
8080
overrides_text = (
8181
", ".join(
82-
f"`{package}={override_version}`"
83-
for package, override_version in sorted(overrides.items())
82+
f"`{package}={spec['version']}`"
83+
for package, spec in sorted(overrides.items())
8484
)
8585
or "-"
8686
)

scenarios/synapse.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,12 @@ def apply_pnpm_workspace_overrides(sdk_dir: Path, overrides: dict) -> bool:
4343
if updated and updated[-1]:
4444
updated.append("")
4545
updated.append("overrides:")
46-
for package, version in sorted(overrides.items()):
47-
updated.append(f" {json.dumps(package)}: {json.dumps(version)}")
46+
for package, spec in sorted(overrides.items()):
47+
updated.append(f" {json.dumps(package)}: {json.dumps(spec['version'])}")
4848

4949
workspace.write_text("\n".join(updated) + "\n")
50-
info(
51-
"Applied pnpm workspace overrides: "
52-
+ ", ".join(
53-
f"{package}={version}" for package, version in sorted(overrides.items())
54-
)
55-
)
50+
for package, spec in sorted(overrides.items()):
51+
info(f"pnpm override {package}={spec['version']} ({spec['reason']})")
5652
return True
5753

5854

scenarios/test_multi_copy_upload.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,12 @@ def setup_filecoin_pin(work_dir: Path) -> tuple[list[str], Path]:
134134
"type=module",
135135
f"dependencies.filecoin-pin={dependency['version']}",
136136
]
137-
for package, version in sorted(overrides.items()):
137+
for package, spec in sorted(overrides.items()):
138+
info(f"npm override {package}={spec['version']} ({spec['reason']})")
138139
package_fields.extend(
139140
[
140-
f"dependencies.{package}={version}",
141-
f"overrides.{package}={version}",
141+
f"dependencies.{package}={spec['version']}",
142+
f"overrides.{package}={spec['version']}",
142143
]
143144
)
144145
run_cmd(

scripts/resolve-ci-dependencies.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,19 @@ def npm_metadata(package: str, version: str, runner=run_command) -> dict:
189189
def validate_overrides(name: str, strategy: str, overrides) -> dict:
190190
if overrides is None:
191191
return {}
192-
if not isinstance(overrides, dict) or not all(
193-
isinstance(key, str) and isinstance(value, str)
194-
for key, value in overrides.items()
195-
):
196-
raise ResolutionError(f"{name} overrides must be a string map")
192+
if not isinstance(overrides, dict):
193+
raise ResolutionError(f"{name} overrides must be a map")
194+
for package, spec in overrides.items():
195+
if (
196+
not isinstance(package, str)
197+
or not isinstance(spec, dict)
198+
or set(spec) != {"version", "reason"}
199+
or not all(isinstance(spec[key], str) and spec[key] for key in spec)
200+
):
201+
raise ResolutionError(
202+
f"{name} override {package!r} must be an object with non-empty "
203+
"string 'version' and 'reason' fields"
204+
)
197205

198206
if name == "synapse-sdk":
199207
return dict(sorted(overrides.items()))

scripts/tests/test_resolve_ci_dependencies.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def test_profile_overrides_are_copied_to_resolved_component(self):
151151
"default": {
152152
"strategy": "npm_version",
153153
"version": "1.0.1",
154-
"overrides": {"multiformats": "14.0.2"},
154+
"overrides": {"nanoid": {"version": "3.3.13", "reason": "test"}},
155155
},
156156
}
157157
runner = FakeRunner(
@@ -177,16 +177,19 @@ def test_profile_overrides_are_copied_to_resolved_component(self):
177177
"filecoin-pin", component, "default", runner
178178
)
179179

180-
self.assertEqual(resolved["overrides"], {"multiformats": "14.0.2"})
180+
self.assertEqual(
181+
resolved["overrides"],
182+
{"nanoid": {"version": "3.3.13", "reason": "test"}},
183+
)
181184

182-
def test_profile_overrides_must_be_string_map(self):
185+
def test_profile_overrides_require_version_and_reason(self):
183186
component = {
184187
"repository": "https://example.test/filecoin-pin.git",
185188
"npm_package": "filecoin-pin",
186189
"default": {
187190
"strategy": "npm_version",
188191
"version": "1.0.1",
189-
"overrides": {"multiformats": 14},
192+
"overrides": {"nanoid": {"version": "3.3.13"}},
190193
},
191194
}
192195
runner = FakeRunner(
@@ -208,7 +211,7 @@ def test_profile_overrides_must_be_string_map(self):
208211
}
209212
)
210213

211-
with self.assertRaisesRegex(resolver.ResolutionError, "overrides"):
214+
with self.assertRaisesRegex(resolver.ResolutionError, "reason"):
212215
resolver.resolve_component("filecoin-pin", component, "default", runner)
213216

214217
def test_overrides_are_rejected_for_core_git_components(self):
@@ -217,7 +220,7 @@ def test_overrides_are_rejected_for_core_git_components(self):
217220
"frontier": {
218221
"strategy": "git_branch",
219222
"branch": "master",
220-
"overrides": {"nanoid": "3.3.13"},
223+
"overrides": {"nanoid": {"version": "3.3.13", "reason": "test"}},
221224
},
222225
}
223226
runner = FakeRunner(
@@ -240,7 +243,7 @@ def test_overrides_are_rejected_for_source_built_filecoin_pin(self):
240243
"frontier": {
241244
"strategy": "git_branch",
242245
"branch": "master",
243-
"overrides": {"multiformats": "14.0.2"},
246+
"overrides": {"nanoid": {"version": "3.3.13", "reason": "test"}},
244247
},
245248
}
246249
runner = FakeRunner(

scripts/tests/test_scenario_dependencies.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,12 @@ def test_dependency_table_contains_all_resolved_components(self):
2121
"source": "git",
2222
"version": "0.41.0",
2323
"commit": "bbb",
24-
"overrides": {"nanoid": "3.3.13"},
24+
"overrides": {"nanoid": {"version": "3.3.13", "reason": "test"}},
2525
},
2626
"filecoin-pin": {
2727
"source": "npm",
2828
"version": "1.0.1",
2929
"commit": "ccc",
30-
"overrides": {"multiformats": "14.0.2"},
3130
},
3231
}
3332
}
@@ -37,11 +36,9 @@ def test_dependency_table_contains_all_resolved_components(self):
3736
"synapse-sdk",
3837
"filecoin-pin",
3938
"nanoid",
40-
"multiformats",
4139
"aaa",
4240
"1.0.1",
4341
"3.3.13",
44-
"14.0.2",
4542
):
4643
self.assertIn(expected, table)
4744

@@ -53,7 +50,7 @@ def test_dependency_table_contains_all_resolved_components(self):
5350
"repository": "https://example.test/synapse.git",
5451
"ref": "sdk-v1.0.0",
5552
"commit": "deadbeef",
56-
"overrides": {"nanoid": "3.3.13"},
53+
"overrides": {"nanoid": {"version": "3.3.13", "reason": "test"}},
5754
},
5855
)
5956
def test_synapse_checkout_uses_resolved_commit(self, _component, run_cmd, _sh):
@@ -86,7 +83,7 @@ def fake_run_cmd(command, **_kwargs):
8683
return_value={
8784
"source": "npm",
8885
"version": "1.0.1",
89-
"overrides": {"multiformats": "14.0.2"},
86+
"overrides": {"nanoid": {"version": "3.3.13", "reason": "test"}},
9087
},
9188
)
9289
def test_filecoin_pin_npm_install_path(self, _component, run_cmd):
@@ -99,11 +96,11 @@ def test_filecoin_pin_npm_install_path(self, _component, run_cmd):
9996
run_cmd.call_args_list[1].args[0],
10097
)
10198
self.assertIn(
102-
"dependencies.multiformats=14.0.2",
99+
"dependencies.nanoid=3.3.13",
103100
run_cmd.call_args_list[1].args[0],
104101
)
105102
self.assertIn(
106-
"overrides.multiformats=14.0.2",
103+
"overrides.nanoid=3.3.13",
107104
run_cmd.call_args_list[1].args[0],
108105
)
109106

0 commit comments

Comments
 (0)