From a0b0c37febd8752cdf1cb74fe80cd1e180056ba8 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 14 Jul 2018 10:21:31 -0300 Subject: [PATCH] Revamp the release script: drop invoke and use tox directly Following the lead from tox, use a simple Python script instead of depending on ``invoke``. Other changes: * Some colors using ``colorama``. * Run ``pre-commit`` before the final commit to ensure everything is neatly formatted. * Drop generating local tag: legacy from the time we used ``devpi`` as staging area, currently we no longer use it, and we should push a tag from the last HEAD of the PR always to ensure it is correct. --- HOWTORELEASE.rst | 14 +---- {tasks => scripts}/release.minor.rst | 0 {tasks => scripts}/release.patch.rst | 0 tasks/generate.py => scripts/release.py | 83 +++++++++++-------------- tasks/__init__.py | 10 --- tasks/requirements.txt | 6 -- tox.ini | 14 +++++ 7 files changed, 55 insertions(+), 72 deletions(-) rename {tasks => scripts}/release.minor.rst (100%) rename {tasks => scripts}/release.patch.rst (100%) rename tasks/generate.py => scripts/release.py (57%) delete mode 100644 tasks/__init__.py delete mode 100644 tasks/requirements.txt diff --git a/HOWTORELEASE.rst b/HOWTORELEASE.rst index b5e852d3b..3d2d6a769 100644 --- a/HOWTORELEASE.rst +++ b/HOWTORELEASE.rst @@ -18,19 +18,11 @@ taking a lot of time to make a new one. Ensure your are in a clean work tree. -#. Install development dependencies in a virtual environment with:: +#. Using ``tox``, generate docs, changelog, announcements:: - $ pip3 install -U -r tasks/requirements.txt - -#. Generate docs, changelog, announcements, and a **local** tag:: - - $ invoke generate.pre-release - -#. Execute pre-commit on all files to ensure the docs are conformant and commit your results:: - - $ pre-commit run --all-files - $ git commit -am "Fix files with pre-commit" + $ tox -e release -- + This will generate a commit with all the changes ready for pushing. #. Open a PR for this branch targeting ``master``. diff --git a/tasks/release.minor.rst b/scripts/release.minor.rst similarity index 100% rename from tasks/release.minor.rst rename to scripts/release.minor.rst diff --git a/tasks/release.patch.rst b/scripts/release.patch.rst similarity index 100% rename from tasks/release.patch.rst rename to scripts/release.patch.rst diff --git a/tasks/generate.py b/scripts/release.py similarity index 57% rename from tasks/generate.py rename to scripts/release.py index 89452aa5c..f187ba585 100644 --- a/tasks/generate.py +++ b/scripts/release.py @@ -1,14 +1,13 @@ """ Invoke development tasks. """ +import argparse +from colorama import init, Fore from pathlib import Path -from subprocess import check_output, check_call - -import invoke +from subprocess import check_output, check_call, call -@invoke.task(help={"version": "version being released"}) -def announce(ctx, version): +def announce(version): """Generates a new release announcement entry in the docs.""" # Get our list of authors stdout = check_output(["git", "describe", "--abbrev=0", "--tags"]) @@ -38,7 +37,7 @@ def announce(ctx, version): "../doc/en/announce/release-{}.rst".format(version) ) target.write_text(text, encoding="UTF-8") - print("[generate.announce] Generated {}".format(target.name)) + print(f"{Fore.CYAN}[generate.announce] {Fore.RESET}Generated {target.name}") # Update index with the new release entry index_path = Path(__file__).parent.joinpath("../doc/en/announce/index.rst") @@ -50,69 +49,63 @@ def announce(ctx, version): 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)) + print( + f"{Fore.CYAN}[generate.announce] {Fore.RESET}Updated {index_path.name}" + ) else: print( - "[generate.announce] Skip {} (already contains release)".format( - index_path.name - ) + f"{Fore.CYAN}[generate.announce] {Fore.RESET}Skip {index_path.name} (already contains release)" ) break check_call(["git", "add", str(target)]) -@invoke.task() -def regen(ctx): +def regen(): """Call regendoc tool to update examples and pytest output in the docs.""" - print("[generate.regen] Updating docs") + print(f"{Fore.CYAN}[generate.regen] {Fore.RESET}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) +def fix_formatting(): + """Runs pre-commit in all files to ensure they are formatted correctly""" + print( + f"{Fore.CYAN}[generate.fix linting] {Fore.RESET}Fixing formatting using pre-commit" + ) + call(["pre-commit", "run", "--all-files"]) -@invoke.task(help={"version": "version being released"}) -def pre_release(ctx, version): +def pre_release(version): """Generates new docs, release announcements and creates a local tag.""" - announce(ctx, version) - regen(ctx) - changelog(ctx, version, write_out=True) + announce(version) + regen() + changelog(version, write_out=True) + fix_formatting() 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.") + print(f"{Fore.CYAN}[generate.pre_release] {Fore.GREEN}All done!") + print() + print(f"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): +def changelog(version, write_out=False): if write_out: addopts = [] else: addopts = ["--draft"] check_call(["towncrier", "--yes", "--version", version] + addopts) + + +def main(): + init(autoreset=True) + parser = argparse.ArgumentParser() + parser.add_argument("version", help="Release version") + options = parser.parse_args() + pre_release(options.version) + + +if __name__ == "__main__": + main() diff --git a/tasks/__init__.py b/tasks/__init__.py deleted file mode 100644 index ea5b1293e..000000000 --- a/tasks/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -Invoke tasks to help with pytest development and release process. -""" - -import invoke - -from . import generate - - -ns = invoke.Collection(generate) diff --git a/tasks/requirements.txt b/tasks/requirements.txt deleted file mode 100644 index db54e76e8..000000000 --- a/tasks/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ --e . -gitpython -invoke -towncrier -tox -wheel diff --git a/tox.ini b/tox.ini index 6e5d7ca68..ae7de1e40 100644 --- a/tox.ini +++ b/tox.ini @@ -176,6 +176,20 @@ commands = coverage report -m coveralls +[testenv:release] +decription = do a release, required posarg of the version number +basepython = python3.6 +skipsdist = True +usedevelop = True +passenv = * +deps = + colorama + gitpython + pre-commit + towncrier + wheel +commands = python scripts/release.py {posargs} + [pytest] minversion = 2.0 plugins = pytester