Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crates publishing script #2604

Merged
merged 16 commits into from
Jul 5, 2023
41 changes: 25 additions & 16 deletions scripts/ci/crates.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,30 +77,39 @@ def crate_deps(member: Dict[str, Dict[str, Any]]) -> Generator[Tuple[str, Depend
yield (v, DependencyKind.BUILD)


def get_sorted_publishable_crates(crates: Dict[str, Crate]) -> Dict[str, Crate]:
def get_sorted_publishable_crates(ctx: Context, crates: Dict[str, Crate]) -> Dict[str, Crate]:
"""
Returns crates topologically sorted in publishing order.

This also filters any crates which have `publish` set to `false`.
"""

def helper(
ctx: Context,
crates: Dict[str, Crate],
name: str,
output: Dict[str, Crate],
visited: Dict[str, bool],
) -> None:
crate = crates[name]
for dependency, _ in crate_deps(crate.manifest):
if dependency not in crates:
continue
helper(crates, dependency, output)
helper(ctx, crates, dependency, output, visited)
# Insert only after all dependencies have been traversed
if "publish" not in crate.manifest["package"] or crate.manifest["package"]["publish"]:
output[name] = crate

if name not in visited:
visited[name] = True
if "publish" not in crate.manifest["package"]:
ctx.error(
f"Crate {Fore.BLUE}{name}{Fore.RESET} does not have {Fore.BLUE}package.publish{Fore.RESET} set."
)
elif crate.manifest["package"]["publish"]:
output[name] = crate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tip: don't put negations in if-statements if there is an else statement. Flip it around and avoid unnecessary negations!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i used .get("publish") here instead to make it a bit clearer


visited: Dict[str, bool] = {}
output: Dict[str, Crate] = {}
for name in crates.keys():
helper(crates, name, output)
helper(ctx, crates, name, output, visited)
return output


Expand Down Expand Up @@ -154,14 +163,15 @@ def publish(self, crate: str, version: str) -> None:
def plan(self, operation: str) -> None:
self.ops.append(operation)

def error(self, e: List[str]) -> None:
def error(self, *e: str) -> None:
self.errors.append("\n".join(e))

def finish(self, dry_run: bool) -> None:
if len(self.errors) > 0:
print("Encountered some errors:")
for error in self.errors:
print(error)
exit(1)
else:
if dry_run:
print("The following operations will be performed:")
Expand Down Expand Up @@ -195,12 +205,10 @@ def bump_dependency_versions(

info = manifest[kind.manifest_key()][dependency]
if isinstance(info, str):
# fmt: off
ctx.error([
ctx.error(
f"{crate}.{dependency} should be specified as:",
f" {dependency} = {{ version = \"" + info + "\" }",
])
# fmt: on
f' {dependency} = {{ version = "' + info + '" }',
)
elif "version" in info:
dependency_version = info["version"]
pin_prefix = "=" if is_pinned(dependency_version) else ""
Expand All @@ -213,13 +221,13 @@ def bump_dependency_versions(


def version(dry_run: bool, bump: Bump) -> None:
ctx = Context()

root: Dict[str, Any] = tomlkit.parse(Path("Cargo.toml").read_text())
crates = get_workspace_crates(root)
current_version = VersionInfo.parse(root["workspace"]["package"]["version"])
new_version = str(bump_fn[bump](current_version))

ctx = Context()

# There are a few places where versions are set:
# 1. In the root `Cargo.toml` under `workspace.package.version`.
bump_package_version(ctx, "(root)", new_version, root["workspace"])
Expand Down Expand Up @@ -250,11 +258,12 @@ def version(dry_run: bool, bump: Bump) -> None:


def publish(dry_run: bool, token: str) -> None:
ctx = Context()

root: Dict[str, Any] = tomlkit.parse(Path("Cargo.toml").read_text())
version = root["workspace"]["package"]["version"]
crates = get_sorted_publishable_crates(get_workspace_crates(root))
crates = get_sorted_publishable_crates(ctx, get_workspace_crates(root))

ctx = Context()
for name in crates.keys():
ctx.publish(name, version)
ctx.finish(dry_run)
Expand Down
Loading