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
48 changes: 44 additions & 4 deletions scripts/publish_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,50 @@ def version_record(self, crate: str, version: str) -> RegistryRecord:


def package_checksums(
manifest: ReleaseManifest, version: str
manifest: ReleaseManifest, version: str, metadata: Mapping[str, Any]
) -> dict[str, str]:
raw_packages = metadata.get("packages")
if not isinstance(raw_packages, list):
raise PublishError("cargo metadata packages must be an array")
packages = {
_string(package.get("name"), "cargo metadata package.name"): package
for raw_package in raw_packages
for package in (_object(raw_package, "cargo metadata package"),)
}
root = ROOT.resolve()
patch_arguments: list[str] = []
for crate in manifest.ordered_crates:
package = packages.get(crate)
if package is None:
raise PublishError(f"cargo metadata is missing release package {crate}")
manifest_path = pathlib.Path(
_string(package.get("manifest_path"), f"{crate}.manifest_path")
).resolve()
package_root = manifest_path.parent
try:
package_root.relative_to(root)
except ValueError:
raise PublishError(
f"release package {crate} is outside the workspace root"
) from None
patch_arguments.extend(
[
"--config",
f"patch.crates-io.{crate}.path={json.dumps(str(package_root))}",
]
)

checksums: dict[str, str] = {}
for crate in manifest.ordered_crates:
command = ["cargo", "package", "--locked", "--no-verify", "-p", crate]
command = [
"cargo",
"package",
"--locked",
"--no-verify",
"-p",
crate,
*patch_arguments,
]
result = subprocess.run(
command, cwd=ROOT, check=False, capture_output=True, text=True
)
Expand Down Expand Up @@ -457,8 +496,9 @@ def _allow_published_rerun() -> bool:

def run(command: str, manifest_path: pathlib.Path) -> None:
manifest = load_release_manifest(manifest_path)
version = validate_release_graph(manifest, cargo_metadata())
checksums = package_checksums(manifest, version)
metadata = cargo_metadata()
version = validate_release_graph(manifest, metadata)
checksums = package_checksums(manifest, version, metadata)
if command == "preflight":
print(
f"packaged {len(checksums)} crates for {version}; release manifest is valid"
Expand Down
52 changes: 52 additions & 0 deletions scripts/tests/test_publish_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
from __future__ import annotations

import subprocess
import tempfile
import unittest
import urllib.error
from pathlib import Path
from unittest import mock

from scripts import publish_release

Expand Down Expand Up @@ -63,6 +66,55 @@ def test_metadata_validation_requires_complete_dependency_ordered_publish_set(se
publish_release.validate_release_graph(incomplete, metadata)


class PackagingTests(unittest.TestCase):
def test_workspace_packages_resolve_unpublished_exact_dependencies_locally(self) -> None:
manifest = publish_release.ReleaseManifest(
ordered_crates=("base", "consumer"),
registry_independent=frozenset({"base"}),
)
with tempfile.TemporaryDirectory() as temporary_directory:
root = Path(temporary_directory)
metadata = {
"packages": [
{
"name": crate,
"manifest_path": str(root / "crates" / crate / "Cargo.toml"),
}
for crate in manifest.ordered_crates
]
}
package_dir = root / "target" / "package"
package_dir.mkdir(parents=True)
for crate in manifest.ordered_crates:
(package_dir / f"{crate}-0.7.3.crate").write_bytes(crate.encode())

commands: list[list[str]] = []

def run(command: list[str], **kwargs: object) -> subprocess.CompletedProcess[str]:
commands.append(command)
self.assertEqual(kwargs["cwd"], root)
return subprocess.CompletedProcess(command, 0, "", "")

with (
mock.patch.object(publish_release, "ROOT", root),
mock.patch.object(publish_release.subprocess, "run", side_effect=run),
):
publish_release.package_checksums(manifest, "0.7.3", metadata)

expected_patches = {
f'patch.crates-io.{crate}.path="{root.resolve() / "crates" / crate}"'
for crate in manifest.ordered_crates
}
self.assertEqual(len(commands), 2)
for command in commands:
configs = {
command[index + 1]
for index, argument in enumerate(command)
if argument == "--config"
}
self.assertEqual(configs, expected_patches)


class RegistryTests(unittest.TestCase):
def test_registry_transport_errors_are_typed_and_retried(self) -> None:
attempts = 0
Expand Down
Loading