from argparse import ArgumentParser
from util import ReleaseRepo
ALL: list[ReleaseRepo] = []
BY_FULL_NAME: dict[str, ReleaseRepo] = {}
def _register(repo: ReleaseRepo) -> None:
ALL.append(repo)
BY_FULL_NAME[repo.gh_full_name] = repo
##################
## Repositories ##
##################
# Repositories managed by this release process should specify their dependencies
# through reservoir name/scope. The versions should be specified via tags, where
# available, or commit hashes otherwise.
# For release `v4.X.0-rc1`, a branch `releases/v4.X.0` is created off of
# `master`. This branch is reused for all subsequent release candidates and
# releases with the same major and minor version, e.g. `v4.X.0`, `v4.X.1`.
#
# `src/CMakeLists.txt` contains the variables LEAN_VERSION_MAJOR,
# LEAN_VERSION_MINOR, LEAN_VERSION_PATCH, and LEAN_VERSION_IS_RELEASE. On
# master, these should point to the next release once the release branch is cut,
# i.e. `v4.X+1.0`, and LEAN_VERSION_IS_RELEASE should be 0. On the release
# branch, these should point to the current release (and updated only when
# necessary for patch releases), and LEAN_VERSION_IS_RELEASE should be 1.
#
# Before creating a release, ensure that no blocking issues/PRs or open backport
# PRs exist. See also the labels `backport releases/v4.X.0` and
# `blocks-release-v4.X.0` on GitHub. There should also be a
# `blocks-release-v4.X+1.0` label corresponding to the CMakeLists version on
# `master`, which should be created after cutting a release branch.
#
# To create a release, push a tag `v4.X.Y` or `v4.X.Y-rcZ`. The tag triggers CI,
# which builds the release artifacts and creates a release on GitHub.
#
# After a release has been created, its description may need to be updated. For
# release candidates, it should read "This is the n-th release candidate for the
# v4.X.Y release of Lean." For releases, it should read "This is the v4.X.Y
# release of Lean. View the release notes for more information." where "release
# notes" is a link to the corresponding release notes section. If the release
# notes has not yet been updated, this second sentence can be omitted and added
# later.
#
# Finally, all the other repos listed below should be updated to use the newly
# released version of Lean.
LEAN4 = ReleaseRepo(github=("leanprover", "lean4"))
# Don't register this repo!
LEAN4_NIGHTLY = ReleaseRepo(github=("leanprover", "lean4-nightly"))
# Don't register this repo!
# To create a new release, open a PR into `main`. In it, bump the toolchain.
#
# For `v4.X.0-rc1` releases, use the existing `bump/v4.X.0` branch. To get the
# latest nightly fixes, you may need to merge the latest
# `bump/nightly-YYYY-MM-DD` PRs, or merge `nightly-testing` directly. After
# merging the PR, create a new `bump/v4.X+1.0` branch off of `main`.
#
# For other releases, create a new branch off of `main` and use it for the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
# Then, update the `stable` branch to point to the same commit.
BATTERIES = ReleaseRepo(
github=("leanprover-community", "batteries"),
bump_branch=True,
release_tag="lean",
stable_branch="stable",
)
_register(BATTERIES)
# To create a new release, open a PR into `master`. In it, bump the toolchain
# and all dependencies. For `v4.X.0-rc1` releases, you may need to merge
# `nightly-testing` into the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
# Then, update the `stable` branch to point to the same commit.
AESOP = ReleaseRepo(
github=("leanprover-community", "aesop"),
release_tag="lean",
stable_branch="stable",
strong_deps=[BATTERIES],
)
_register(AESOP)
# To create a new release, open a PR into `main`. In it, bump the toolchain and
# all dependencies. For `v4.X.0-rc1` releases, you may need to merge
# `nightly-testing` into the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
LEAN4_CLI = ReleaseRepo(
github=("leanprover", "lean4-cli"),
release_tag="lean",
)
_register(LEAN4_CLI)
# To create a new release, open a PR into `main`. In it, bump the toolchain and
# all dependencies. For `v4.X.0-rc1` releases, you may need to merge
# `nightly-testing` into the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
IMPORT_GRAPH = ReleaseRepo(
github=("leanprover-community", "import-graph"),
release_tag="lean",
strong_deps=[LEAN4_CLI],
)
_register(IMPORT_GRAPH)
# To create a new release, open a PR into `main`. In it, bump the toolchain. For
# `v4.X.0-rc1` releases, you may need to merge `nightly-testing` into the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
PLAUSIBLE = ReleaseRepo(
github=("leanprover-community", "plausible"),
release_tag="lean",
)
_register(PLAUSIBLE)
# To create a new release, open a PR into `main`. In it, bump the toolchain. For
# `v4.X.0-rc1` releases, you may need to merge `nightly-testing` into the PR.
#
# Obtain the next ProofWidgets version number by incrementing the patch version
# of the latest release (which will have the form `v0.0.X`). Once the release PR
# is merged, tag the resulting commit with the new version number.
PROOFWIDGETS4 = ReleaseRepo(
github=("leanprover-community", "ProofWidgets4"),
release_tag="proofwidgets",
)
_register(PROOFWIDGETS4)
# To create a new release, open a PR into `main`. In it, bump the toolchain. For
# `v4.X.0-rc1` releases, you may need to merge `nightly-testing` into the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
# Then, update the `stable` branch to point to the same commit.
QUOTE4 = ReleaseRepo(
github=("leanprover-community", "quote4"),
release_tag="lean",
stable_branch="stable",
)
_register(QUOTE4)
# To create a new release, open a PR into `master`. In it, bump the toolchain
# and all dependencies.
#
# For `v4.X.0-rc1` releases, use the existing `bump/v4.X.0` branch from the
# nightly repo. To get the latest nightly fixes, you may need to merge the
# latest `bump/nightly-YYYY-MM-DD` PRs, or merge `nightly-testing` directly.
# After merging the PR, create a new `bump/v4.X+1.0` branch off of `master`.
#
# For other releases, create a new branch off of `master` and use it for the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
# Then, update the `stable` branch to point to the same commit.
MATHLIB4 = ReleaseRepo(
github=("leanprover-community", "mathlib4"),
nightly=ReleaseRepo(github=("leanprover-community", "mathlib4-nightly-testing")),
bump_branch=True,
release_tag="lean",
stable_branch="stable",
strong_deps=[BATTERIES, QUOTE4, AESOP, PROOFWIDGETS4, IMPORT_GRAPH, PLAUSIBLE],
)
_register(MATHLIB4)
# To create a new release, open a PR into `main`. In it, bump the toolchain and
# all dependencies.
#
# For `v4.X.0-rc1` releases, use the existing `bump/v4.X.0` branch. To get the
# latest nightly fixes, you may need to merge the latest
# `bump/nightly-YYYY-MM-DD` PRs, or merge `nightly-testing` directly. After
# merging the PR, create a new `bump/v4.X+1.0` branch off of `main`.
#
# For other releases, create a new branch off of `main` and use it for the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
# Then, update the `stable` branch to point to the same commit.
CSLIB = ReleaseRepo(
github=("leanprover", "cslib"),
bump_branch=True,
release_tag="lean",
stable_branch="stable",
strong_deps=[MATHLIB4],
)
_register(CSLIB)
# To create a new release, open a PR into `main`. In it, bump the toolchain and
# all dependencies. Also bump the toolchain and deps in `test/Mathlib`. Maybe
# run the tests locally before creating the PR? For `v4.X.0-rc1` releases, you
# may need to merge `nightly-testing` into the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
# Then, update the `stable` branch to point to the same commit.
REPL = ReleaseRepo(
github=("leanprover-community", "repl"),
release_tag="lean",
stable_branch="stable",
strong_deps=[MATHLIB4], # For tests in CI
)
_register(REPL)
# To create a new release, open a PR into `main`. In it, bump the toolchain and
# all dependencies, then run `update-subverso.sh`. For `v4.X.0-rc1` releases,
# you may need to merge `nightly-testing` into the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
VERSO = ReleaseRepo(
github=("leanprover", "verso"),
release_tag="lean",
strong_deps=[PLAUSIBLE],
weak_deps=[MATHLIB4], # For benchmarks
)
_register(VERSO)
# To create a new release, open a PR into `main`. In it, bump the toolchain and
# all dependencies. For `v4.X.0-rc1` releases, you may need to merge
# `nightly-testing` into the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
VERSO_WEB_COMPONENTS = ReleaseRepo(
github=("leanprover", "verso-web-components"),
release_tag="lean",
strong_deps=[VERSO],
)
_register(VERSO_WEB_COMPONENTS)
# To bump the toolchain, open a PR into `main`. In it, bump the toolchain and
# all dependencies.
#
# For `v4.X.0-rc1` releases, generate a new set of release notes and ensure
# they're imported and linked. For other releases, regenerate the existing
# release notes. For `v4.X.0-rc1` releases, you may also need to merge
# `nightly-testing` into the PR.
#
# Once the toolchain bump PR is merged, tag the resulting commit with the lean
# version. If the tag already exists, it may need to be updated manually.
#
# Highlights should be added in a separate PR and merged only shortly before the
# final release. That way, they don't get in the way of the RC bumps and can be
# commented on by the other developers.
REFERENCE_MANUAL = ReleaseRepo(
github=("leanprover", "reference-manual"),
release_tag="lean",
strong_deps=[VERSO_WEB_COMPONENTS, VERSO],
)
_register(REFERENCE_MANUAL)
# To create a new release, open a PR into `main`. In it, bump the toolchain and
# all dependencies. Also bump the toolchain and dependencies in `examples/hero`.
# Finally, run `scripts/update.sh`. For `v4.X.0-rc1` releases, you may need to
# merge `nightly-testing` into the PR.
LEAN_FRO_ORG = ReleaseRepo(
github=("leanprover", "lean-fro.org"),
strong_deps=[VERSO, VERSO_WEB_COMPONENTS],
)
_register(LEAN_FRO_ORG)
# To create a new release, trigger the "Update Toolchain" CI workflow and wait
# for it to open a PR, then merge the PR if it looks good. For non-RC releases,
# wait for the maintainer to release a new version.
LEAN4_UNICODE_BASIC = ReleaseRepo(
github=("fgdorais", "lean4-unicode-basic"),
)
_register(LEAN4_UNICODE_BASIC)
# To create a new release, open a PR into `master`. In it, bump the toolchain
# and all dependencies. For `v4.X.0-rc1` releases, you may need to merge
# `nightly-testing` into the PR.
BIBTEX_QUERY = ReleaseRepo(
github=("dupuisf", "BibtexQuery"),
release_tag="lean",
strong_deps=[LEAN4_UNICODE_BASIC],
)
_register(BIBTEX_QUERY)
# To create a new release, open a PR into `master`. In it, bump the toolchain
# and all dependencies.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
LEANSQLITE = ReleaseRepo(
github=("leanprover", "leansqlite"),
release_tag="lean",
strong_deps=[PLAUSIBLE],
)
_register(LEANSQLITE)
# To create a new release, open a PR into `main`. In it, bump the toolchain and
# all dependencies. For `v4.X.0-rc1` releases, you may need to merge
# `nightly-testing` into the PR.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
DOC_GEN4 = ReleaseRepo(
github=("leanprover", "doc-gen4"),
release_tag="lean",
strong_deps=[BIBTEX_QUERY, LEAN4_UNICODE_BASIC, LEAN4_CLI, LEANSQLITE],
# Doc-gen4 shouldn't lag behind mathlib if possible because of downstream
# users, and doc-gen4 benchmarks failing for a short while is an acceptable
# price to pay for that.
# https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Tagging.20commits.20in.20mathlib4/near/585725955
ignored_deps=[MATHLIB4], # For benchmarks
)
_register(DOC_GEN4)
BATTERIES.ignored_deps.append(DOC_GEN4)
# To create a new release, open a PR into `master`. In it, bump the toolchain
# and all dependencies.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
COMPARATOR = ReleaseRepo(
github=("leanprover", "comparator"),
release_tag="lean",
)
_register(COMPARATOR)
# To create a new release, open a PR into `master`. In it, bump the toolchain
# and all dependencies.
#
# Once the release PR is merged, tag the resulting commit with the lean version.
LEAN4EXPORT = ReleaseRepo(
github=("leanprover", "lean4export"),
release_tag="lean",
)
_register(LEAN4EXPORT)
###################
## Visualization ##
###################
def transitive_strong_deps(repo: ReleaseRepo) -> set[str]:
result = set()
for dep in repo.strong_deps:
result.add(dep.gh_full_name)
result |= transitive_strong_deps(dep)
return result
def indirect_strong_deps(repo: ReleaseRepo) -> set[str]:
result = set()
for dep in repo.strong_deps:
result |= transitive_strong_deps(dep)
return result
def graphviz_attrs(**kwargs: str) -> str:
if not kwargs:
return ""
style_str = " ".join(f"{k}=<{v}>" for k, v in kwargs.items())
return f" [{style_str}]"
def print_graphviz_line(
repo: ReleaseRepo,
dep: ReleaseRepo,
comment: bool = False,
attrs: dict[str, str] | None = None,
) -> None:
comment_str = "// " if comment else ""
attrs_str = graphviz_attrs(**attrs or {})
print(f' {comment_str}"{dep.gh_full_name}" -> "{repo.gh_full_name}"{attrs_str};')
def print_graphviz_dot(
prune: bool = True, no_weak: bool = False, no_ignored: bool = False
) -> None:
print("digraph G {")
print(" rankdir=LR;")
for repo in sorted(ALL, key=lambda r: r.gh_full_name):
indirect = indirect_strong_deps(repo)
# label = f"{repo.gh_owner}{repo.gh_name}"
label = f'{repo.gh_owner}
{repo.gh_name}'
attrs = {"label": label}
if repo.completed:
attrs["style"] = "filled"
attrs["color"] = "palegreen"
print(f' "{repo.gh_full_name}"{graphviz_attrs(**attrs)};')
for dep in repo.strong_deps:
comment = prune and dep.gh_full_name in indirect
print_graphviz_line(repo, dep, comment=comment)
for dep in repo.weak_deps:
comment = no_weak or (prune and dep.gh_full_name in indirect)
print_graphviz_line(repo, dep, comment=comment, attrs={"style": "dashed"})
for dep in repo.ignored_deps:
comment = no_ignored or (prune and dep.gh_full_name in indirect)
attrs = {"style": "dashed", "color": "red", "constraint": "false"}
print_graphviz_line(repo, dep, comment=comment, attrs=attrs)
print("}")
def print_all_urls() -> None:
for repo in ALL:
print(f"- {repo.gh_url}")
def clone_all_repos() -> None:
for repo in ALL:
print(f"Cloning {repo.gh_full_name}...")
repo.local.prepare()
class Args:
graph: bool
prune: bool
no_weak: bool
no_ignored: bool
urls: bool
clone: bool
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("-g", "--graph", action="store_true")
parser.add_argument("-p", "--prune", action="store_true")
parser.add_argument("-W", "--no-weak", action="store_true")
parser.add_argument("-I", "--no-ignored", action="store_true")
parser.add_argument("-u", "--urls", action="store_true")
parser.add_argument("-c", "--clone", action="store_true")
args = parser.parse_args(namespace=Args())
if args.graph:
print_graphviz_dot(
prune=args.prune, no_weak=args.no_weak, no_ignored=args.no_ignored
)
if args.urls:
print_all_urls()
if args.clone:
clone_all_repos()