diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f216fbc73cf..b201462dd23 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -505,6 +505,48 @@ repos: - --py-version=3.9 - --platform=linux + # ----- Invoke ----------------------------------------------------------------------------------------------------> + - id: pip-tools-compile + alias: compile-py3.5-invoke-requirements + name: Linux Py3.5 Invoke Requirements + files: ^requirements/static/invoke\.in$ + args: + - -v + - --py-version=3.5 + + - id: pip-tools-compile + alias: compile-py3.6-invoke-requirements + name: Linux Py3.6 Invoke Requirements + files: ^requirements/static/invoke\.in$ + args: + - -v + - --py-version=3.6 + + - id: pip-tools-compile + alias: compile-py3.7-invoke-requirements + name: Linux Py3.7 Invoke Requirements + files: ^requirements/static/invoke\.in$ + args: + - -v + - --py-version=3.7 + + - id: pip-tools-compile + alias: compile-py3.8-invoke-requirements + name: Linux Py3.8 Invoke Requirements + files: ^requirements/static/invoke\.in$ + args: + - -v + - --py-version=3.8 + + - id: pip-tools-compile + alias: compile-py3.9-invoke-requirements + name: Linux Py3.9 Invoke Requirements + files: ^requirements/static/invoke\.in$ + args: + - -v + - --py-version=3.9 + # <---- Invoke ----------------------------------------------------------------------------------------------------- + - repo: https://github.com/timothycrosley/isort rev: "1e78a9acf3110e1f9721feb591f89a451fc9876a" hooks: @@ -539,7 +581,7 @@ repos: - id: nox-py2 alias: lint-salt name: Lint Salt - files: ^((setup|noxfile)|salt/.*)\.py$ + files: ^((setup|noxfile)|(salt|tasks)/.*)\.py$ args: - -e - lint-salt-pre-commit diff --git a/noxfile.py b/noxfile.py index 886004ecae7..61807417c33 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1031,7 +1031,7 @@ def lint_salt(session): if session.posargs: paths = session.posargs else: - paths = ["setup.py", "noxfile.py", "salt/"] + paths = ["setup.py", "noxfile.py", "salt/", "tasks/"] _lint(session, ".pylintrc", flags, paths) @@ -1133,3 +1133,72 @@ def docs_man(session, compress, update): if compress: session.run("tar", "-cJvf", "man-archive.tar.xz", "_build/man", external=True) os.chdir("..") + + +def _invoke(session): + """ + Run invoke tasks + """ + requirements_file = "requirements/static/invoke.in" + distro_constraints = [ + "requirements/static/{}/invoke.txt".format(_get_pydir(session)) + ] + install_command = ["--progress-bar=off", "-r", requirements_file] + for distro_constraint in distro_constraints: + install_command.extend(["--constraint", distro_constraint]) + session.install(*install_command, silent=PIP_INSTALL_SILENT) + cmd = ["inv"] + files = [] + + # Unfortunately, invoke doesn't support the nargs functionality like argpase does. + # Let's make it behave properly + for idx, posarg in enumerate(session.posargs): + if idx == 0: + cmd.append(posarg) + continue + if posarg.startswith("--"): + cmd.append(posarg) + continue + files.append(posarg) + if files: + cmd.append("--files={}".format(" ".join(files))) + session.run(*cmd) + + +@nox.session(name="invoke", python="3") +def invoke(session): + _invoke(session) + + +@nox.session(name="invoke-pre-commit", python="3") +def invoke_pre_commit(session): + if "VIRTUAL_ENV" not in os.environ: + session.error( + "This should be running from within a virtualenv and " + "'VIRTUAL_ENV' was not found as an environment variable." + ) + if "pre-commit" not in os.environ["VIRTUAL_ENV"]: + session.error( + "This should be running from within a pre-commit virtualenv and " + "'VIRTUAL_ENV'({}) does not appear to be a pre-commit virtualenv.".format( + os.environ["VIRTUAL_ENV"] + ) + ) + from nox.virtualenv import VirtualEnv + + # Let's patch nox to make it run inside the pre-commit virtualenv + try: + session._runner.venv = VirtualEnv( # pylint: disable=unexpected-keyword-arg + os.environ["VIRTUAL_ENV"], + interpreter=session._runner.func.python, + reuse_existing=True, + venv=True, + ) + except TypeError: + # This is still nox-py2 + session._runner.venv = VirtualEnv( + os.environ["VIRTUAL_ENV"], + interpreter=session._runner.func.python, + reuse_existing=True, + ) + _invoke(session) diff --git a/requirements/static/invoke.in b/requirements/static/invoke.in new file mode 100644 index 00000000000..2c48557fd18 --- /dev/null +++ b/requirements/static/invoke.in @@ -0,0 +1,2 @@ +invoke +blessings diff --git a/requirements/static/py3.5/invoke.txt b/requirements/static/py3.5/invoke.txt new file mode 100644 index 00000000000..3386dce93ae --- /dev/null +++ b/requirements/static/py3.5/invoke.txt @@ -0,0 +1,9 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile -o requirements/static/py3.5/invoke.txt -v requirements/static/invoke.in +# +blessings==1.7 +invoke==1.4.1 +six==1.14.0 # via blessings diff --git a/requirements/static/py3.6/invoke.txt b/requirements/static/py3.6/invoke.txt new file mode 100644 index 00000000000..0272e488434 --- /dev/null +++ b/requirements/static/py3.6/invoke.txt @@ -0,0 +1,9 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile -o requirements/static/py3.6/invoke.txt -v requirements/static/invoke.in +# +blessings==1.7 +invoke==1.4.1 +six==1.14.0 # via blessings diff --git a/requirements/static/py3.7/invoke.txt b/requirements/static/py3.7/invoke.txt new file mode 100644 index 00000000000..b2784255ab4 --- /dev/null +++ b/requirements/static/py3.7/invoke.txt @@ -0,0 +1,9 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile -o requirements/static/py3.7/invoke.txt -v requirements/static/invoke.in +# +blessings==1.7 +invoke==1.4.1 +six==1.14.0 # via blessings diff --git a/requirements/static/py3.8/invoke.txt b/requirements/static/py3.8/invoke.txt new file mode 100644 index 00000000000..4f1cd2b1c0c --- /dev/null +++ b/requirements/static/py3.8/invoke.txt @@ -0,0 +1,9 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile -o requirements/static/py3.8/invoke.txt -v requirements/static/invoke.in +# +blessings==1.7 +invoke==1.4.1 +six==1.14.0 # via blessings diff --git a/requirements/static/py3.9/invoke.txt b/requirements/static/py3.9/invoke.txt new file mode 100644 index 00000000000..9e101a5d86c --- /dev/null +++ b/requirements/static/py3.9/invoke.txt @@ -0,0 +1,9 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile -o requirements/static/py3.9/invoke.txt -v requirements/static/invoke.in +# +blessings==1.7 +invoke==1.4.1 +six==1.14.0 # via blessings diff --git a/tasks/README.md b/tasks/README.md new file mode 100644 index 00000000000..6ff3fb10a7d --- /dev/null +++ b/tasks/README.md @@ -0,0 +1,28 @@ +# What is this directory? + +This directory contains python scripts which should be called by [invoke](https://pypi.org/project/invoke). + +Instead of having several multi-purpose python scripts scatered through multiple paths in the salt code base, +we will now concentrate them under an invoke task. + +## Calling Invoke + +Invoke can be called in the following ways. + +### Installed system-wide + +If invoke is installed system-wide, be sure you also have `blessings` installed if you want coloured output, although +it's not a hard requirement. + +``` +inv docs.check +``` + +### Using Nox + +Since salt already uses nox, and nox manages virtual environments and respective requirements, calling invoke is as +simple as: + +``` +nox -e invoke -- docs.check +``` diff --git a/tasks/__init__.py b/tasks/__init__.py new file mode 100644 index 00000000000..45e4eb3be5c --- /dev/null +++ b/tasks/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +from invoke import Collection # pylint: disable=3rd-party-module-not-gated + +ns = Collection() diff --git a/tasks/utils.py b/tasks/utils.py new file mode 100644 index 00000000000..50cfa7f98e0 --- /dev/null +++ b/tasks/utils.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +""" + tasks.utils + ~~~~~~~~~~~ + Invoke utilities +""" + +import sys + +try: + from blessings import Terminal + + terminal = Terminal() + HAS_BLESSINGS = True +except ImportError: + terminal = None + HAS_BLESSINGS = False + + +def exit_invoke(exitcode, message=None, *args, **kwargs): + if message is not None: + if exitcode > 0: + warn(message, *args, **kwargs) + else: + info(message, *args, **kwargs) + sys.exit(exitcode) + + +def info(message, *args, **kwargs): + if not isinstance(message, str): + message = str(message) + message = message.format(*args, **kwargs) + if terminal: + message = terminal.bold(terminal.green(message)) + write_message(message) + + +def warn(message, *args, **kwargs): + if not isinstance(message, str): + message = str(message) + message = message.format(*args, **kwargs) + if terminal: + message = terminal.bold(terminal.yellow(message)) + write_message(message) + + +def error(message, *args, **kwargs): + if not isinstance(message, str): + message = str(message) + message = message.format(*args, **kwargs) + if terminal: + message = terminal.bold(terminal.red(message)) + write_message(message) + + +def write_message(message): + sys.stderr.write(message) + if not message.endswith("\n"): + sys.stderr.write("\n") + sys.stderr.flush()