Skip to content

Commit e66e5ed

Browse files
andystaplesCopilot
andcommitted
Detect future major prerelease upgrades
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 2cbf63d commit e66e5ed

3 files changed

Lines changed: 34 additions & 7 deletions

File tree

‎azure-functions-durable/README.md‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,12 @@ After the first durable-client, orchestrator, or entity invocation,
3838
each Python worker checks accessible `requirements.txt` files in the
3939
background and writes a host worker log warning when the declared constraints
4040
permit a later major version. The check follows local `-r` and `-c` files and
41-
applicable environment markers. It is best-effort: missing or unsupported
42-
requirements are treated as unknown. A lockfile's presence does not indicate
43-
whether deployment uses it, so the warning describes the risk of installing
44-
directly from the requirements. The check does not read dependency files during
45-
app startup or wait for the check before returning from an invocation.
41+
applicable environment markers. It is best-effort and may miss uncommon version
42+
ranges; missing or unsupported requirements are treated as unknown. A
43+
lockfile's presence does not indicate whether deployment uses it, so the warning
44+
describes the risk of installing directly from the requirements. The check does
45+
not read dependency files during app startup or wait for the check before
46+
returning from an invocation.
4647

4748
## Overview
4849

‎azure-functions-durable/azure/durable_functions/internal/dependency_warning.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ def add_release(epoch: int, major: int, minor: int, patch: int) -> None:
130130
add_release(bound.epoch, bound.major, bound.minor + 1, 0)
131131
add_release(bound.epoch, bound.major + 1, 0, 0)
132132

133+
for candidate in tuple(candidates):
134+
base = candidate.base_version
135+
candidates.update(Version(f"{base}{suffix}") for suffix in (".dev0", "a0", "b0", "rc0"))
136+
if candidate.pre and candidate.pre[1] > 0:
137+
label, number = candidate.pre
138+
candidates.add(Version(f"{base}{label}{number - 1}"))
139+
133140
allowed = [candidate for candidate in candidates if specifiers.contains(candidate, prereleases=True)]
134141
return (
135142
any(candidate.major == installed.major for candidate in allowed)

‎tests/azure-functions-durable/test_dependency_warning.py‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,20 @@ def _warnings(caplog):
3232
("azure-functions-durable>=2.0.0b1", True),
3333
("azure-functions-durable>=2,<4", True),
3434
("azure-functions-durable>=2,<3.1", True),
35+
("azure-functions-durable>=2.0.0rc5,<3.0.0rc2", True),
36+
("azure-functions-durable>=2.0.0rc5,<3.0.0rc0", True),
37+
("azure-functions-durable>=2.0.0rc5,<3.0.0a0", True),
38+
("--pre\nazure-functions-durable>=2.0.0rc5,<=3.0.0,!=3.0.0", True),
39+
(
40+
"azure-functions-durable>=2.0.0rc5,<3.0.0rc2,"
41+
"!=3.0.0.dev0,!=3.0.0a0,!=3.0.0b0,!=3.0.0rc0",
42+
True,
43+
),
3544
("azure-functions-durable!=3.*", True),
3645
("azure-functions-durable!=3.0.0", True),
3746
("azure-functions-durable<3", False),
3847
("azure-functions-durable>=2.0.0b1,<3", False),
48+
("azure-functions-durable>=2.0.0rc5,<3.0.0.dev0", False),
3949
("azure-functions-durable==2.*", False),
4050
("azure-functions-durable==2.0.0rc5", False),
4151
("azure-functions-durable~=2.0", False),
@@ -72,6 +82,14 @@ def test_suggested_constraint_preserves_the_installed_epoch(monkeypatch, tmp_pat
7282
assert "azure-functions-durable>=1!2.3,<1!3" in _warnings(caplog)[0]
7383

7484

85+
def test_future_major_prerelease_preserves_the_installed_epoch(monkeypatch, tmp_path, caplog):
86+
monkeypatch.setattr(dependency_warning, "version", lambda name: "1!2.0rc5")
87+
(tmp_path / "requirements.txt").write_text(
88+
"azure-functions-durable>=1!2.0rc5,<1!3.0rc2", encoding="utf-8")
89+
dependency_warning.warn_if_unbounded(str(tmp_path), logging.getLogger(__name__))
90+
assert "azure-functions-durable>=1!2.0rc5,<1!3" in _warnings(caplog)[0]
91+
92+
7593
def test_a_higher_major_in_an_older_epoch_is_not_an_upgrade(monkeypatch, tmp_path, caplog):
7694
monkeypatch.setattr(dependency_warning, "version", lambda name: "1!2.0")
7795
(tmp_path / "requirements.txt").write_text("azure-functions-durable>=2,<1!3", encoding="utf-8")
@@ -320,9 +338,10 @@ async def async_fail():
320338

321339
wrapped = invocation.wrap_invocation(async_fail if use_async else fail)
322340
with pytest.raises(ValueError, match="invocation failed"):
323-
result = wrapped(context=context)
324341
if use_async:
325-
await result
342+
await wrapped(context=context)
343+
else:
344+
wrapped(context=context)
326345

327346
assert checked == [context]
328347
assert invocation.get_invocation_id() is None

0 commit comments

Comments
 (0)