diff --git a/.azure-pipelines/jobs/package.yml b/.azure-pipelines/jobs/package.yml index 7a3837df2..2070bc5d4 100644 --- a/.azure-pipelines/jobs/package.yml +++ b/.azure-pipelines/jobs/package.yml @@ -15,13 +15,13 @@ jobs: inputs: versionSpec: '3' - - bash: pip install setuptools tox wheel invoke towncrier requests + - bash: pip install tox nox setuptools wheel displayName: Install dependencies - - bash: invoke generate.authors + - bash: nox -s generate_authors displayName: Generate AUTHORS.txt - - bash: invoke generate.news --yes + - bash: nox -s generate_news -- --yes displayName: Generate NEWS.rst - bash: tox -e packaging diff --git a/.gitignore b/.gitignore index 44e20d24a..946385eef 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ docs/build/ .mypy_cache/ # Unit test / coverage reports -.tox/ +.[nt]ox/ htmlcov/ .coverage .coverage.* diff --git a/MANIFEST.in b/MANIFEST.in index 747f84ad4..5bf20b0d9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -17,6 +17,7 @@ exclude .appveyor.yml exclude .travis.yml exclude .readthedocs.yml exclude tox.ini +exclude noxfile.py recursive-include src/pip/_vendor *.pem recursive-include docs Makefile *.rst *.py *.bat diff --git a/docs/html/development/release-process.rst b/docs/html/development/release-process.rst index a3de68459..a01ce71df 100644 --- a/docs/html/development/release-process.rst +++ b/docs/html/development/release-process.rst @@ -80,14 +80,13 @@ Creating a new release ---------------------- #. Checkout the current pip ``master`` branch. -#. Ensure you have the latest ``wheel``, ``setuptools``, ``twine``, ``invoke`` - and ``towncrier`` packages installed. -#. Generate a new ``AUTHORS.txt`` (``invoke generate.authors``) and commit the +#. Ensure you have the latest ``wheel``, ``setuptools``, ``twine`` and ``nox`` packages installed. +#. Generate a new ``AUTHORS.txt`` (``nox -s generate_authors``) and commit the results. #. Bump the version in ``pip/__init__.py`` to the release version and commit the results. Usually this involves dropping just the ``.devN`` suffix on the version. -#. Generate a new ``NEWS.rst`` (``invoke generate.news``) and commit the +#. Generate a new ``NEWS.rst`` (``nox -s generate_news``) and commit the results. #. Create a tag at the current commit, of the form ``YY.N`` (``git tag YY.N``). diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 000000000..d6357b3dd --- /dev/null +++ b/noxfile.py @@ -0,0 +1,55 @@ +"""Release time helpers, executed using nox. +""" + +import io +import subprocess + +import nox + + +def get_author_list(): + """Get the list of authors from Git commits. + """ + # subprocess because session.run doesn't give us stdout + result = subprocess.run( + ["git", "log", "--use-mailmap", "--format=%aN <%aE>"], + capture_output=True, + encoding="utf-8", + ) + + # Create a unique list. + authors = [] + seen_authors = set() + for author in result.stdout.splitlines(): + author = author.strip() + if author.lower() not in seen_authors: + seen_authors.add(author.lower()) + authors.append(author) + + # Sort our list of Authors by their case insensitive name + return sorted(authors, key=lambda x: x.lower()) + + +# ----------------------------------------------------------------------------- +# Commands used during the release process +# ----------------------------------------------------------------------------- +@nox.session +def generate_authors(session): + # Get our list of authors + session.log("Collecting author names") + authors = get_author_list() + + # Write our authors to the AUTHORS file + session.log("Writing AUTHORS") + with io.open("AUTHORS.txt", "w", encoding="utf-8") as fp: + fp.write(u"\n".join(authors)) + fp.write(u"\n") + + +@nox.session +def generate_news(session): + session.log("Generating NEWS") + session.install("towncrier") + + # You can pass 2 possible arguments: --draft, --yes + session.run("towncrier", *session.posargs) diff --git a/setup.cfg b/setup.cfg index 4c6f7c5f1..81396f9ba 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,7 @@ [isort] skip = ./build, + .nox, .tox, .scratch, _vendor, @@ -17,6 +18,7 @@ include_trailing_comma = true [flake8] exclude = ./build, + .nox, .tox, .scratch, _vendor, diff --git a/tasks/__init__.py b/tasks/__init__.py index ecde43996..6427f6037 100644 --- a/tasks/__init__.py +++ b/tasks/__init__.py @@ -1,5 +1,5 @@ import invoke -from tools.automation import generate, vendoring +from tools.automation import vendoring -ns = invoke.Collection(generate, vendoring) +ns = invoke.Collection(vendoring) diff --git a/tools/automation/generate.py b/tools/automation/generate.py deleted file mode 100644 index 235789707..000000000 --- a/tools/automation/generate.py +++ /dev/null @@ -1,47 +0,0 @@ -import io - -import invoke - - -@invoke.task -def authors(ctx): - print("[generate.authors] Generating AUTHORS") - - # Get our list of authors - print("[generate.authors] Collecting author names") - - # Note that it's necessary to use double quotes in the - # --format"=%aN <%aE>" part of the command, as the Windows - # shell doesn't recognise single quotes here. - r = ctx.run('git log --use-mailmap --format"=%aN <%aE>"', - encoding="utf-8", hide=True) - - authors = [] - seen_authors = set() - for author in r.stdout.splitlines(): - author = author.strip() - if author.lower() not in seen_authors: - seen_authors.add(author.lower()) - authors.append(author) - - # Sort our list of Authors by their case insensitive name - authors = sorted(authors, key=lambda x: x.lower()) - - # Write our authors to the AUTHORS file - print("[generate.authors] Writing AUTHORS") - with io.open("AUTHORS.txt", "w", encoding="utf8") as fp: - fp.write(u"\n".join(authors)) - fp.write(u"\n") - - -@invoke.task -def news(ctx, draft=False, yes=False): - print("[generate.news] Generating NEWS") - - args = [] - if draft: - args.append("--draft") - if yes: - args.append("--yes") - - ctx.run("towncrier {}".format(" ".join(args)))