""" Invoke development tasks. """ from pathlib import Path from subprocess import check_output, check_call import invoke @invoke.task(help={"version": "version being released"}) def announce(ctx, version): """Generates a new release announcement entry in the docs.""" # Get our list of authors stdout = check_output(["git", "describe", "--abbrev=0", "--tags"]) stdout = stdout.decode("utf-8") last_version = stdout.strip() stdout = check_output( ["git", "log", "{}..HEAD".format(last_version), "--format=%aN"] ) stdout = stdout.decode("utf-8") contributors = set(stdout.splitlines()) template_name = ( "release.minor.rst" if version.endswith(".0") else "release.patch.rst" ) template_text = ( Path(__file__).parent.joinpath(template_name).read_text(encoding="UTF-8") ) contributors_text = ( "\n".join("* {}".format(name) for name in sorted(contributors)) + "\n" ) text = template_text.format(version=version, contributors=contributors_text) target = Path(__file__).parent.joinpath( "../doc/en/announce/release-{}.rst".format(version) ) target.write_text(text, encoding="UTF-8") print("[generate.announce] Generated {}".format(target.name)) # Update index with the new release entry index_path = Path(__file__).parent.joinpath("../doc/en/announce/index.rst") lines = index_path.read_text(encoding="UTF-8").splitlines() indent = " " for index, line in enumerate(lines): if line.startswith("{}release-".format(indent)): new_line = indent + target.stem if line != new_line: lines.insert(index, new_line) index_path.write_text("\n".join(lines) + "\n", encoding="UTF-8") print("[generate.announce] Updated {}".format(index_path.name)) else: print( "[generate.announce] Skip {} (already contains release)".format( index_path.name ) ) break check_call(["git", "add", str(target)]) @invoke.task() def regen(ctx): """Call regendoc tool to update examples and pytest output in the docs.""" print("[generate.regen] Updating docs") check_call(["tox", "-e", "regen"]) @invoke.task() def make_tag(ctx, version): """Create a new, local tag for the release, only if the repository is clean.""" from git import Repo repo = Repo(".") if repo.is_dirty(): print("Current repository is dirty. Please commit any changes and try again.") raise invoke.Exit(code=2) tag_names = [x.name for x in repo.tags] if version in tag_names: print("[generate.make_tag] Delete existing tag {}".format(version)) repo.delete_tag(version) print("[generate.make_tag] Create tag {}".format(version)) repo.create_tag(version) @invoke.task(help={"version": "version being released"}) def pre_release(ctx, version): """Generates new docs, release announcements and creates a local tag.""" announce(ctx, version) regen(ctx) changelog(ctx, version, write_out=True) msg = "Preparing release version {}".format(version) check_call(["git", "commit", "-a", "-m", msg]) make_tag(ctx, version) print() print("[generate.pre_release] Please push your branch and open a PR.") @invoke.task( help={ "version": "version being released", "write_out": "write changes to the actual changelog", } ) def changelog(ctx, version, write_out=False): if write_out: addopts = [] else: addopts = ["--draft"] check_call(["towncrier", "--yes", "--version", version] + addopts)