This commit is contained in:
benedettadavico
2026-02-27 18:56:27 +01:00
parent a399a75b03
commit 3531901a17
3 changed files with 6 additions and 132 deletions
+1 -132
View File
@@ -67,138 +67,7 @@ jobs:
- name: Preflight publish checks
run: |
python3 - <<'PY'
import tomllib
import pathlib
import sys
root = pathlib.Path(".")
ws = tomllib.loads((root / "Cargo.toml").read_text())
members = ws["workspace"]["members"]
errors = []
workspace_members = {}
for member in members:
manifest = root / member / "Cargo.toml"
if not manifest.exists():
continue
data = tomllib.loads(manifest.read_text())
package = data.get("package")
if not package:
continue
publish = package.get("publish", True)
publishable = publish is not False
workspace_members[package.get("name", member)] = {
"member": member,
"manifest": manifest,
"publishable": publishable,
"data": data,
}
def dependency_sections(crate_data):
for section in ("dependencies", "dev-dependencies", "build-dependencies"):
deps = crate_data.get(section, {})
if isinstance(deps, dict):
yield section, deps
target = crate_data.get("target", {})
if isinstance(target, dict):
for target_name, target_data in target.items():
if not isinstance(target_data, dict):
continue
for section in ("dependencies", "dev-dependencies", "build-dependencies"):
deps = target_data.get(section, {})
if isinstance(deps, dict):
yield f"target.{target_name}.{section}", deps
def resolve_workspace_dep_name(dep_name, spec, manifest):
if not isinstance(spec, dict):
return None
if spec.get("workspace") is True:
return dep_name
candidate = spec.get("package", dep_name)
if candidate in workspace_members:
return candidate
dep_path = spec.get("path")
if not dep_path:
return None
dep_manifest = (manifest.parent / dep_path / "Cargo.toml").resolve()
if not dep_manifest.exists():
return None
dep_data = tomllib.loads(dep_manifest.read_text())
dep_package = dep_data.get("package", {})
resolved_name = dep_package.get("name")
if resolved_name in workspace_members:
return resolved_name
return None
for member in members:
manifest = root / member / "Cargo.toml"
if not manifest.exists():
continue
data = tomllib.loads(manifest.read_text())
package = data.get("package")
if not package:
continue
if package.get("publish", True) is False:
continue
crate_name = package.get("name", member)
for field in ("description", "license", "repository"):
value = package.get(field)
has_value = (
(isinstance(value, str) and bool(value.strip()))
or (isinstance(value, dict) and value.get("workspace") is True)
)
if not has_value:
errors.append(
f"{member}: package '{crate_name}' missing required field '{field}'"
)
for section, dependencies in dependency_sections(data):
for dep_name, spec in dependencies.items():
if isinstance(spec, dict) and "path" in spec:
if spec.get("workspace") is True:
continue
if "version" not in spec:
errors.append(
f"{member}: {section} '{dep_name}' uses path dependency without version ({spec['path']})"
)
resolved_dep = resolve_workspace_dep_name(dep_name, spec, manifest)
if (
resolved_dep
and resolved_dep in workspace_members
and not workspace_members[resolved_dep]["publishable"]
):
errors.append(
f"{member}: package '{crate_name}' ({section}) depends on non-publishable workspace crate '{resolved_dep}'"
)
workspace_deps = ws.get("workspace", {}).get("dependencies", {})
for dep_name, spec in workspace_deps.items():
if isinstance(spec, dict) and "path" in spec and "version" not in spec:
errors.append(
f"workspace.dependencies: '{dep_name}' has path but no version"
)
if errors:
print("Preflight checks failed:")
for err in errors:
print(f"- {err}")
sys.exit(1)
print("Preflight checks passed.")
PY
python3 tools/internal/check_publish_preflight.py
# Dry run may show cascading dependency errors because packages aren't
# actually uploaded - these are expected and ignored. We check for real
@@ -25,6 +25,10 @@ jobs:
- name: Install cargo-workspaces
run: cargo install cargo-workspaces
- name: Preflight publish checks
run: |
python3 tools/internal/check_publish_preflight.py
- name: Publish remaining crates
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
+1
View File
@@ -10,6 +10,7 @@ license.workspace = true
rust-version.workspace = true
readme.workspace = true
version.workspace = true
publish = false
[dependencies]
thiserror = { workspace = true }