Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/crates-io-maintenance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
- name: Install Rust 1.86
uses: dtolnay/rust-toolchain@4d407b29186a635f0cc27475ef0bc0ae605a8866 # 1.86.0

- name: Audit discovery and exact prerelease installation
- name: Audit discovery and exact release installation
run: >-
python3 scripts/ci/maintain-crates-io.py audit
--evidence crates-io-audit-evidence.json
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 2.0.0

- Publish the stable Rust SDK qualified against the immutable Server `2.0.0`
artifact.

## 2.0.0-rc.39

- Qualify this prerelease against the immutable Server `2.0.0-rc.68` artifact
Expand Down
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "durable-workflow"
version = "2.0.0-rc.39"
version = "2.0.0"
edition = "2021"
description = "First-party Rust SDK for Durable Workflow workers and clients"
license = "MIT"
Expand All @@ -14,10 +14,10 @@ categories = ["api-bindings", "asynchronous"]
include = ["/src/**", "/schema/**", "/examples/**", "/Cargo.toml", "/README.md", "/CHANGELOG.md", "/LICENSE"]

[package.metadata.durable-workflow]
product-train = "2.0.0-rc.39"
product-train = "2.0.0"
compatibility-authority = "protocol-manifests"
supported-server-versions = "2.0.0-rc.68"
qualified-server-version = "2.0.0-rc.68"
supported-server-versions = "2.0.0"
qualified-server-version = "2.0.0"
worker-protocol-version = "1.19"
server-worker-protocol-versions = ">=1.19,<2.0"
portable-worker-affinity-minimum-worker-protocol-version = "1.18"
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,5 @@ the authoritative source for the `durable-workflow` crate and its Rust API
documentation.

Crate releases follow semantic versioning and are tagged with the exact crate
version. During the 2.0 beta, the crate advances with the synchronized product
train. After stable 2.0, fixes, additive capabilities, and breaking changes use
ordinary patch, minor, and major progression respectively.
version. Starting with stable 2.0, fixes, additive capabilities, and breaking
changes use ordinary patch, minor, and major progression respectively.
12 changes: 6 additions & 6 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<title>Durable Workflow for Rust</title>
<script type="module" src="/analytics/analytics.js"></script>
</head>
<body class="dw-landing" data-landing-contract="general-rust-first" data-source-version="2.0.0-rc.39" data-rust-version="1.86">
<body class="dw-landing" data-landing-contract="general-rust-first" data-source-version="2.0.0" data-rust-version="1.86">
<header class="dw-nav" data-landing-region="primary-navigation">
<a class="dw-brand" href="/" aria-label="Durable Workflow Rust home">
<span class="dw-brand__mark" aria-hidden="true">DW</span>
Expand All @@ -24,11 +24,11 @@

<main>
<header class="dw-page-heading" data-journey="general">
<p class="dw-kicker">Rust SDK · 2.0 prerelease</p>
<p class="dw-kicker">Rust SDK · 2.0 stable</p>
<h1>Durable Workflow Rust SDK</h1>
<p data-landing-lead>Author deterministic workflows and activities, run workers, and control workflow executions with the first-party Rust SDK.</p>
<p class="dw-version">
<strong>Supported prerelease channel</strong>
<strong>Supported 2.0 release</strong>
<span>Resolved by the public compatibility authority</span>
<span>Requires Rust 1.86+</span>
</p>
Expand Down Expand Up @@ -57,8 +57,8 @@ <h3>Confirm the Rust toolchain</h3>
<li>
<span class="dw-step-number">2</span>
<div>
<h3>Install the prerelease channel</h3>
<p>Let the public compatibility authority select the qualified crate in the 2.0 RC line.</p>
<h3>Install the supported SDK</h3>
<p>Let the public compatibility authority select the supported crate in the 2.0 line.</p>
<pre><code>curl -fsSL https://durable-workflow.com/install-sdk.sh | sh -s -- rust</code></pre>
</div>
</li>
Expand Down Expand Up @@ -104,7 +104,7 @@ <h2 id="cloud-title">Durable Workflow Cloud</h2>

<footer>
<span>Durable Workflow Rust SDK</span>
<span>Explicit 2.0 prerelease documentation</span>
<span>Stable 2.0 documentation</span>
</footer>
</body>
</html>
33 changes: 20 additions & 13 deletions scripts/ci/maintain-crates-io.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ def is_2_0_release_candidate(version: str) -> bool:
)


def is_supported_2_0_release(version: str) -> bool:
major, minor, patch, prerelease = parse_semver(version)
return (major, minor, patch) == (2, 0, 0) and (
prerelease is None or prerelease.startswith("rc.")
)


def load_authority(
plan_path: Path, manifest_path: Path
) -> tuple[dict[str, Any], str, str]:
Expand Down Expand Up @@ -168,12 +175,12 @@ def load_authority(
raise MaintenanceError(
"authority_mismatch", "manifest and retirement plan name different packages"
)
if not isinstance(current_version, str) or not is_2_0_release_candidate(
if not isinstance(current_version, str) or not is_supported_2_0_release(
current_version
):
raise MaintenanceError(
"stable_release_not_authorized",
"registry maintenance requires the manifest to name an exact 2.0 release candidate",
"registry maintenance requires an exact supported 2.0 release",
)
return plan, current_version, hashlib.sha256(plan_bytes).hexdigest()

Expand Down Expand Up @@ -331,20 +338,20 @@ def registry_violations(

exact = observation["current_exact_version"]
if exact["state"] != "active":
violations.append(f"current_release_candidate_not_active:{current_version}")
violations.append(f"current_release_not_active:{current_version}")
elif not exact.get("registry_response", {}).get("checksum"):
violations.append(
f"current_release_candidate_checksum_missing:{current_version}"
)
violations.append(f"current_release_checksum_missing:{current_version}")
root = observation["crate_root"]
if root["newest_version"] != current_version:
violations.append("crate_root_newest_version_is_not_current_release_candidate")
violations.append("crate_root_newest_version_is_not_current_release")
if require_retired and root["default_version"] != current_version:
violations.append("crate_root_default_version_is_not_current_release_candidate")
violations.append("crate_root_default_version_is_not_current_release")
for candidate in observation["release_candidates"]:
if candidate["yanked"] is True:
violations.append(f"release_candidate_yanked:{candidate['version']}")
if observation["stable_2_versions"]:
_, _, _, current_prerelease = parse_semver(current_version)
authorized_stable_versions = [current_version] if current_prerelease is None else []
if observation["stable_2_versions"] != authorized_stable_versions:
violations.append("stable_2_release_exists_without_authorization")
return violations

Expand All @@ -360,7 +367,7 @@ def base_evidence(
"environment_variable": "CARGO_REGISTRY_TOKEN",
"value_recorded": False,
},
"current_release_candidate": current_version,
"current_release": current_version,
"generated_at": utc_now(),
"operation": operation,
"outcome": "pending",
Expand Down Expand Up @@ -543,13 +550,13 @@ def verify_exact_install(
if len(matches) != 1:
raise MaintenanceError(
"exact_requirement_resolved_incorrectly",
"Cargo did not resolve the exact current release candidate",
"Cargo did not resolve the exact current release",
)
resolved = matches[0]
if resolved.get("checksum") != expected_checksum:
raise MaintenanceError(
"registry_checksum_mismatch",
"Cargo.lock and crates.io report different checksums for the current release candidate",
"Cargo.lock and crates.io report different checksums for the current release",
)
return {
"credential_available": False,
Expand Down Expand Up @@ -581,7 +588,7 @@ def audit(
evidence["violations"] = violations
raise MaintenanceError(
"live_registry_audit_failed",
"crates.io discovery does not match the supported prerelease policy",
"crates.io discovery does not match the supported release policy",
)
checksum = observation["current_exact_version"]["registry_response"]["checksum"]
evidence["exact_installation"] = verify_exact_install(
Expand Down
2 changes: 1 addition & 1 deletion scripts/ci/publish-rust-sdk.sh
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ if [[ "$package_version" != "$product_train" ]]; then
printf 'Rust SDK package version must match its product train metadata: %s, %s\n' "$package_version" "$product_train" >&2
exit 1
fi
if [[ "$compatibility_authority" != "protocol-manifests" || "$server_compatibility" != "2.0.0-rc.68" || "$qualified_server_version" != "2.0.0-rc.68" || "$server_worker_protocols" != ">=1.19,<2.0" ]]; then
if [[ "$compatibility_authority" != "protocol-manifests" || "$server_compatibility" != "2.0.0" || "$qualified_server_version" != "2.0.0" || "$server_worker_protocols" != ">=1.19,<2.0" ]]; then
printf 'unexpected Rust SDK supported Server contract: %s, %s, %s, %s\n' "$compatibility_authority" "$server_compatibility" "$qualified_server_version" "$server_worker_protocols" >&2
exit 1
fi
Expand Down
7 changes: 5 additions & 2 deletions scripts/ci/qualify-docs-landing.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
EXACT_PRERELEASE_VERSION = re.compile(
r"\b\d+\.\d+\.\d+-(?:alpha|beta|rc)\.\d+\b"
)
EXACT_RELEASE_VERSION = re.compile(
r"\d+\.\d+\.\d+(?:-(?:alpha|beta|rc)\.\d+)?"
)
VISIBLE_CARGO_PATH = re.compile(
r"\bcargo\s+add\s+durable-workflow\b|\bdurable-workflow\s*="
)
Expand Down Expand Up @@ -433,9 +436,9 @@ def qualified_rust_version(contract_text: str) -> str:
artifacts = contract.get("artifacts")
rust = artifacts.get("sdk-rust") if isinstance(artifacts, dict) else None
version = rust.get("version") if isinstance(rust, dict) else None
if not isinstance(version, str) or EXACT_PRERELEASE_VERSION.fullmatch(version) is None:
if not isinstance(version, str) or EXACT_RELEASE_VERSION.fullmatch(version) is None:
raise QualificationError(
"public quickstart authority is missing a qualified Rust prerelease"
"public quickstart authority is missing a qualified Rust release"
)
return version

Expand Down
4 changes: 2 additions & 2 deletions scripts/ci/test-maintain-crates-io.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def test_plan_names_every_historical_final_and_no_prerelease(self) -> None:
for version in self.plan["retired_versions"]
)
)
self.assertTrue(maintenance.is_2_0_release_candidate(self.current))
self.assertTrue(maintenance.is_supported_2_0_release(self.current))

def test_retirement_yanks_only_active_reviewed_versions(self) -> None:
registry = FakeRegistry(self.plan, self.current)
Expand Down Expand Up @@ -192,7 +192,7 @@ def test_live_audit_rejects_stale_default_discovery(self) -> None:
install.assert_not_called()
evidence = json.loads(evidence_path.read_text(encoding="utf-8"))
self.assertIn(
"crate_root_default_version_is_not_current_release_candidate",
"crate_root_default_version_is_not_current_release",
evidence["violations"],
)

Expand Down
6 changes: 3 additions & 3 deletions scripts/ci/test-publish-rust-sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
PUBLISH = ROOT / "scripts" / "ci" / "publish-rust-sdk.sh"
RELEASE_WORKFLOW = ROOT / ".github" / "workflows" / "release.yml"
RELEASE_TOOLING_INSTALLER = ROOT / "scripts" / "ci" / "install-release-tooling.sh"
PACKAGE_VERSION = "2.0.0-rc.39"
PACKAGE_VERSION = "2.0.0"
PRODUCT_TRAIN = PACKAGE_VERSION
SERVER_VERSIONS = "2.0.0-rc.68"
QUALIFIED_SERVER_VERSION = "2.0.0-rc.68"
SERVER_VERSIONS = "2.0.0"
QUALIFIED_SERVER_VERSION = "2.0.0"
WORKER_PROTOCOL_VERSION = "1.19"
SERVER_WORKER_PROTOCOLS = ">=1.19,<2.0"
RELEASE_COMMIT = "0123456789abcdef0123456789abcdef01234567"
Expand Down
14 changes: 13 additions & 1 deletion scripts/ci/test-qualify-docs-landing.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ def test_source_ahead_of_public_authority_keeps_install_guidance_truthful(self)
self.assertEqual(self.source_version, body.attrs.get("data-source-version"))
self.assertNotIn("data-crate-version", body.attrs)

def test_stable_public_authority_is_accepted(self) -> None:
public_version = QUALIFIER.qualified_rust_version(
json.dumps(
{
"schema": QUALIFIER.QUICKSTART_CONTRACT_SCHEMA,
"artifacts": {"sdk-rust": {"version": "2.0.0"}},
}
)
)

self.assertEqual("2.0.0", public_version)

def test_rejects_a_floating_cargo_requirement_in_visible_onboarding(self) -> None:
floating_onboarding = self.html.replace(
'<p class="dw-version">',
Expand All @@ -125,7 +137,7 @@ def test_rejects_a_floating_cargo_requirement_in_visible_onboarding(self) -> Non
def test_rejects_an_exact_prerelease_version_in_visible_onboarding(self) -> None:
pinned_onboarding = self.html.replace(
'<p class="dw-version">',
f'<p class="dw-version"><span>Qualified crate {self.source_version}</span>',
'<p class="dw-version"><span>Qualified crate 2.0.0-rc.99</span>',
1,
)

Expand Down
2 changes: 1 addition & 1 deletion tests/onboarding_version_pins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn visible_html_text(content: &str) -> String {
}

#[test]
fn onboarding_uses_the_prerelease_channel() {
fn onboarding_uses_the_versionless_supported_channel() {
for (path, content) in [
("README.md", include_str!("../README.md")),
("docs/index.html", include_str!("../docs/index.html")),
Expand Down