mirror of
https://github.com/ansible/awx.git
synced 2026-10-31 14:36:17 -02:30
AAP-85334: Replace Black + Flake8 with Ruff
Migrate Python linting and formatting toolchain from Black (formatter) and Flake8 (linter) to Ruff, which provides both in a single tool. - pyproject.toml: remove [tool.black], add [tool.ruff] config sections - tox.ini: replace black+flake8 deps/commands with ruff in linters env - awxkit/tox.ini: replace flake8 with ruff in lint env - Makefile: replace `black` target with `format` + `lint`, keep `black` as legacy alias, update `check` and `api-lint` - pre-commit.sh: use `ruff format --check`, honor AWX_IGNORE_RUFF - requirements_dev.txt: swap black/flake8 for ruff - Dockerfile.j2: install ruff instead of black - CONTRIBUTING.md: update tool references - Fix noqa comments to use # separator instead of ; (ruff requirement) - Add noqa: F841 for false positive in awxkit/cli/__init__.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
b84931a49b
commit
4b73e1264b
+2
-2
@@ -109,7 +109,7 @@ Install the pre-commit hook before contributing:
|
|||||||
make pre-commit
|
make pre-commit
|
||||||
```
|
```
|
||||||
|
|
||||||
When you attempt to perform a `git commit` there will be a pre-commit hook that gets run before the commit is allowed to your local repository. For example, python's [black](https://pypi.org/project/black/) will be run to test the formatting of any python files.
|
When you attempt to perform a `git commit` there will be a pre-commit hook that gets run before the commit is allowed to your local repository. For example, [ruff](https://docs.astral.sh/ruff/) will be run to check the formatting of any python files.
|
||||||
|
|
||||||
While you can use environment variables to skip the pre-commit hooks GitHub will run similar tests and prevent merging of PRs if the tests do not pass.
|
While you can use environment variables to skip the pre-commit hooks GitHub will run similar tests and prevent merging of PRs if the tests do not pass.
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ Fixes and Features for AWX will go through the Github pull request process. Subm
|
|||||||
Here are a few things you can do to help the visibility of your change, and increase the likelihood that it will be accepted:
|
Here are a few things you can do to help the visibility of your change, and increase the likelihood that it will be accepted:
|
||||||
|
|
||||||
- No issues when running linters/code checkers
|
- No issues when running linters/code checkers
|
||||||
- Python: black: `(container)/awx_devel$ make black`
|
- Python: ruff: `(container)/awx_devel$ make format`
|
||||||
- No issues from unit tests
|
- No issues from unit tests
|
||||||
- Python: py.test: `(container)/awx_devel$ make test`
|
- Python: py.test: `(container)/awx_devel$ make test`
|
||||||
- Write tests for new functionality, update/add tests for bug fixes
|
- Write tests for new functionality, update/add tests for bug fixes
|
||||||
|
|||||||
@@ -348,9 +348,17 @@ run-ws-heartbeat:
|
|||||||
reports:
|
reports:
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
black: reports
|
## awx_collection is excluded: ansible-test sanity runs its own linters which conflict with ruff
|
||||||
@command -v black >/dev/null 2>&1 || { echo "could not find black on your PATH, you may need to \`pip install black\`, or set AWX_IGNORE_BLACK=1" && exit 1; }
|
format: reports
|
||||||
@(set -o pipefail && $@ $(BLACK_ARGS) awx awxkit awx_collection | tee reports/$@.report)
|
@command -v ruff >/dev/null 2>&1 || { echo "could not find ruff on your PATH, you may need to \`pip install ruff\`" && exit 1; }
|
||||||
|
@(set -o pipefail && ruff format $(RUFF_FORMAT_ARGS) awx awxkit | tee reports/format.report)
|
||||||
|
|
||||||
|
lint: reports
|
||||||
|
@command -v ruff >/dev/null 2>&1 || { echo "could not find ruff on your PATH, you may need to \`pip install ruff\`" && exit 1; }
|
||||||
|
ruff check awx awxkit
|
||||||
|
|
||||||
|
## Legacy alias
|
||||||
|
black: format
|
||||||
|
|
||||||
$(GIT_COMMON_DIR)/hooks/pre-commit:
|
$(GIT_COMMON_DIR)/hooks/pre-commit:
|
||||||
ln -sf ../../pre-commit.sh $(GIT_COMMON_DIR)/hooks/pre-commit
|
ln -sf ../../pre-commit.sh $(GIT_COMMON_DIR)/hooks/pre-commit
|
||||||
@@ -369,11 +377,11 @@ genschema-yaml: awx-link reports
|
|||||||
fi; \
|
fi; \
|
||||||
$(MANAGEMENT_COMMAND) spectacular --format openapi --file schema.yaml
|
$(MANAGEMENT_COMMAND) spectacular --format openapi --file schema.yaml
|
||||||
|
|
||||||
check: black
|
check: format
|
||||||
|
|
||||||
api-lint:
|
api-lint:
|
||||||
BLACK_ARGS="--check" $(MAKE) black
|
RUFF_FORMAT_ARGS="--check" $(MAKE) format
|
||||||
flake8 awx
|
$(MAKE) lint
|
||||||
yamllint -s .
|
yamllint -s .
|
||||||
|
|
||||||
## Run egg_info_dev to generate awx.egg-info for development.
|
## Run egg_info_dev to generate awx.egg-info for development.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from awx.api.versioning import reverse
|
|||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from ansible_base.jwt_consumer.common.util import generate_x_trusted_proxy_header
|
from ansible_base.jwt_consumer.common.util import generate_x_trusted_proxy_header
|
||||||
from ansible_base.lib.testing.fixtures import rsa_keypair_factory, rsa_keypair # noqa: F401; pylint: disable=unused-import
|
from ansible_base.lib.testing.fixtures import rsa_keypair_factory, rsa_keypair # noqa: F401 # pylint: disable=unused-import
|
||||||
|
|
||||||
|
|
||||||
class HeaderTrackingMiddleware(object):
|
class HeaderTrackingMiddleware(object):
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from rest_framework.exceptions import ValidationError
|
|||||||
|
|
||||||
# DAB
|
# DAB
|
||||||
from ansible_base.jwt_consumer.common.util import generate_x_trusted_proxy_header
|
from ansible_base.jwt_consumer.common.util import generate_x_trusted_proxy_header
|
||||||
from ansible_base.lib.testing.fixtures import rsa_keypair_factory, rsa_keypair # noqa: F401; pylint: disable=unused-import
|
from ansible_base.lib.testing.fixtures import rsa_keypair_factory, rsa_keypair # noqa: F401 # pylint: disable=unused-import
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@@ -161,7 +161,7 @@ def test_invalid_json_body(patch, job_template_factory, alice, json_body):
|
|||||||
objs = job_template_factory('jt', organization='org1')
|
objs = job_template_factory('jt', organization='org1')
|
||||||
objs.job_template.admin_role.members.add(alice)
|
objs.job_template.admin_role.members.add(alice)
|
||||||
resp = patch(reverse('api:job_template_detail', kwargs={'pk': objs.job_template.id}), json_body, alice, expect=400)
|
resp = patch(reverse('api:job_template_detail', kwargs={'pk': objs.job_template.id}), json_body, alice, expect=400)
|
||||||
assert resp.data['detail'] == (u'JSON parse error - not a JSON object')
|
assert resp.data['detail'] == ('JSON parse error - not a JSON object')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@@ -432,7 +432,7 @@ class TestJobTemplateCallbackProxyIntegration:
|
|||||||
data={'host_config_key': 'abcd'},
|
data={'host_config_key': 'abcd'},
|
||||||
user=admin_user,
|
user=admin_user,
|
||||||
expect=expected,
|
expect=expected,
|
||||||
**headers
|
**headers,
|
||||||
)
|
)
|
||||||
|
|
||||||
@override_settings(REMOTE_HOST_HEADERS=['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST'], PROXY_IP_ALLOWED_LIST=[])
|
@override_settings(REMOTE_HOST_HEADERS=['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST'], PROXY_IP_ALLOWED_LIST=[])
|
||||||
@@ -462,7 +462,7 @@ class TestJobTemplateCallbackProxyIntegration:
|
|||||||
data={'host_config_key': 'abcd'},
|
data={'host_config_key': 'abcd'},
|
||||||
user=admin_user,
|
user=admin_user,
|
||||||
expect=201,
|
expect=201,
|
||||||
**headers
|
**headers,
|
||||||
)
|
)
|
||||||
|
|
||||||
@override_settings(REMOTE_HOST_HEADERS=['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST'], PROXY_IP_ALLOWED_LIST=['my.proxy.example.org'])
|
@override_settings(REMOTE_HOST_HEADERS=['HTTP_X_FROM_THE_LOAD_BALANCER', 'REMOTE_ADDR', 'REMOTE_HOST'], PROXY_IP_ALLOWED_LIST=['my.proxy.example.org'])
|
||||||
@@ -483,5 +483,5 @@ class TestJobTemplateCallbackProxyIntegration:
|
|||||||
data={'host_config_key': 'abcd'},
|
data={'host_config_key': 'abcd'},
|
||||||
user=admin_user,
|
user=admin_user,
|
||||||
expect=400,
|
expect=400,
|
||||||
**headers
|
**headers,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from awx.api.versioning import reverse
|
|||||||
# These tests are invoked from the awx/main/tests/live/ subfolder
|
# These tests are invoked from the awx/main/tests/live/ subfolder
|
||||||
# so any fixtures from higher-up conftest files must be explicitly included
|
# so any fixtures from higher-up conftest files must be explicitly included
|
||||||
from awx.main.tests.functional.conftest import * # noqa
|
from awx.main.tests.functional.conftest import * # noqa
|
||||||
from awx.main.tests.conftest import load_all_credentials # noqa: F401; pylint: disable=unused-import
|
from awx.main.tests.conftest import load_all_credentials # noqa: F401 # pylint: disable=unused-import
|
||||||
from awx.main.tests import data
|
from awx.main.tests import data
|
||||||
|
|
||||||
from awx.main.models import Project, JobTemplate, Organization, Inventory, WorkflowJob, UnifiedJob
|
from awx.main.models import Project, JobTemplate, Organization, Inventory, WorkflowJob, UnifiedJob
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ import logging
|
|||||||
|
|
||||||
# In this module we don't use EXPORTABLE_RESOURCES, we just want to validate that our installed awxkit has import/export
|
# In this module we don't use EXPORTABLE_RESOURCES, we just want to validate that our installed awxkit has import/export
|
||||||
try:
|
try:
|
||||||
from awxkit.api.pages.api import EXPORTABLE_RESOURCES # noqa: F401; pylint: disable=unused-import
|
from awxkit.api.pages.api import EXPORTABLE_RESOURCES # noqa: F401 # pylint: disable=unused-import
|
||||||
|
|
||||||
HAS_EXPORTABLE_RESOURCES = True
|
HAS_EXPORTABLE_RESOURCES = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ from ansible_base.rbac.models import RoleDefinition, DABPermission
|
|||||||
from ansible_base.rbac import permission_registry
|
from ansible_base.rbac import permission_registry
|
||||||
|
|
||||||
from awx.main.migrations._dab_rbac import setup_managed_role_definitions
|
from awx.main.migrations._dab_rbac import setup_managed_role_definitions
|
||||||
from awx.main.tests.conftest import load_all_credentials # noqa: F401; pylint: disable=unused-import
|
from awx.main.tests.conftest import load_all_credentials # noqa: F401 # pylint: disable=unused-import
|
||||||
from awx.main.tests.functional.conftest import _request
|
from awx.main.tests.functional.conftest import _request
|
||||||
from awx.main.tests.functional.conftest import credentialtype_scm, credentialtype_ssh # noqa: F401; pylint: disable=unused-import
|
from awx.main.tests.functional.conftest import credentialtype_scm, credentialtype_ssh # noqa: F401 # pylint: disable=unused-import
|
||||||
from awx.main.models import (
|
from awx.main.models import (
|
||||||
Organization,
|
Organization,
|
||||||
Project,
|
Project,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import pytest
|
|||||||
from awx.main.models.execution_environments import ExecutionEnvironment
|
from awx.main.models.execution_environments import ExecutionEnvironment
|
||||||
from awx.main.models.jobs import JobTemplate
|
from awx.main.models.jobs import JobTemplate
|
||||||
|
|
||||||
from awx.main.tests.functional.conftest import user, system_auditor # noqa: F401; pylint: disable=unused-import
|
from awx.main.tests.functional.conftest import user, system_auditor # noqa: F401 # pylint: disable=unused-import
|
||||||
|
|
||||||
|
|
||||||
ASSETS = set([
|
ASSETS = set([
|
||||||
|
|||||||
@@ -26,10 +26,8 @@ def run(stdout=sys.stdout, stderr=sys.stderr, argv=[]):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except ConnectionError as e:
|
except ConnectionError as e:
|
||||||
cli.parser.print_help()
|
cli.parser.print_help()
|
||||||
msg = (
|
msg = '\nThere was a network error of some kind trying to reach {}.\nYou might need to specify (or double-check) --conf.host'.format(
|
||||||
'\nThere was a network error of some kind trying to reach '
|
cli.get_config('host')
|
||||||
'{}.\nYou might need to specify (or double-check) '
|
|
||||||
'--conf.host'.format(cli.get_config('host'))
|
|
||||||
)
|
)
|
||||||
if isinstance(e, SSLError):
|
if isinstance(e, SSLError):
|
||||||
msg = (
|
msg = (
|
||||||
@@ -60,7 +58,7 @@ def run(stdout=sys.stdout, stderr=sys.stderr, argv=[]):
|
|||||||
sys.stdout.write(e.__class__.__name__)
|
sys.stdout.write(e.__class__.__name__)
|
||||||
print('')
|
print('')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except Exception as e:
|
except Exception as e: # noqa: F841
|
||||||
if cli.verbose:
|
if cli.verbose:
|
||||||
e = traceback.format_exc()
|
e = traceback.format_exc()
|
||||||
cprint(e, 'red', file=stderr)
|
cprint(e, 'red', file=stderr)
|
||||||
|
|||||||
+2
-7
@@ -26,11 +26,9 @@ commands =
|
|||||||
[testenv:lint]
|
[testenv:lint]
|
||||||
deps =
|
deps =
|
||||||
{[testenv]deps}
|
{[testenv]deps}
|
||||||
flake8
|
ruff
|
||||||
commands =
|
commands =
|
||||||
flake8 awxkit
|
ruff check awxkit
|
||||||
# pylama --report report.pylama awxkit
|
|
||||||
# py.test awxkit --pylama --junitxml=report.pylama {posargs}
|
|
||||||
- coverage erase
|
- coverage erase
|
||||||
|
|
||||||
[testenv:coveralls]
|
[testenv:coveralls]
|
||||||
@@ -39,9 +37,6 @@ commands=
|
|||||||
- coverage report -m
|
- coverage report -m
|
||||||
- coveralls
|
- coveralls
|
||||||
|
|
||||||
[flake8]
|
|
||||||
max-line-length = 120
|
|
||||||
|
|
||||||
[pytest]
|
[pytest]
|
||||||
addopts = -v --tb=native
|
addopts = -v --tb=native
|
||||||
testpaths = test
|
testpaths = test
|
||||||
|
|||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
if [ -z $AWX_IGNORE_BLACK ] ; then
|
if [ -z "$AWX_IGNORE_BLACK" ] && [ -z "$AWX_IGNORE_RUFF" ] ; then
|
||||||
python_files_changed=$(git diff --cached --name-only --diff-filter=AM awx/ awxkit/ tools/ | grep -E '\.py$')
|
python_files_changed=$(git diff --cached --name-only --diff-filter=AM awx/ awxkit/ tools/ | grep -E '\.py$')
|
||||||
if [ "x$python_files_changed" != "x" ] ; then
|
if [ "x$python_files_changed" != "x" ] ; then
|
||||||
black --check $python_files_changed || \
|
ruff format --check $python_files_changed || \
|
||||||
if [ $? != 0 ] ; then
|
if [ $? != 0 ] ; then
|
||||||
echo 'To fix this, run `make black` to auto-format your code prior to commit, or set AWX_IGNORE_BLACK=1'
|
echo 'To fix this, run `make format` to auto-format your code prior to commit, or set AWX_IGNORE_RUFF=1'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
+13
-4
@@ -6,8 +6,17 @@ build-backend = "setuptools.build_meta"
|
|||||||
# causes the "version" key in setup.cfg to be ignored.
|
# causes the "version" key in setup.cfg to be ignored.
|
||||||
# [tool.setuptools_scm]
|
# [tool.setuptools_scm]
|
||||||
|
|
||||||
[tool.black]
|
[tool.ruff]
|
||||||
line-length = 160
|
line-length = 160
|
||||||
fast = true
|
extend-exclude = ["awx_collection"]
|
||||||
skip-string-normalization = true
|
|
||||||
extend-exclude = "awx_collection"
|
[tool.ruff.format]
|
||||||
|
quote-style = "preserve"
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = [
|
||||||
|
"E722",
|
||||||
|
"F401", "F402", "F405", "F523", "F541",
|
||||||
|
"F811", "F821", "F822", "F841",
|
||||||
|
"W291", "W605",
|
||||||
|
]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ openapi-spec-validator # OpenAPI 3.0 schema validation
|
|||||||
# pprofile - re-add once https://github.com/vpelletier/pprofile/issues/41 is addressed
|
# pprofile - re-add once https://github.com/vpelletier/pprofile/issues/41 is addressed
|
||||||
ipython>=7.31.1 # https://github.com/ansible/awx/security/dependabot/30
|
ipython>=7.31.1 # https://github.com/ansible/awx/security/dependabot/30
|
||||||
unittest2
|
unittest2
|
||||||
black
|
ruff
|
||||||
pytest!=7.0.0
|
pytest!=7.0.0
|
||||||
pytest-asyncio
|
pytest-asyncio
|
||||||
pytest-cov
|
pytest-cov
|
||||||
@@ -21,7 +21,6 @@ jupyter
|
|||||||
backports.tempfile # support in unit tests for py32+ tempfile.TemporaryDirectory
|
backports.tempfile # support in unit tests for py32+ tempfile.TemporaryDirectory
|
||||||
gprof2dot
|
gprof2dot
|
||||||
atomicwrites
|
atomicwrites
|
||||||
flake8
|
|
||||||
yamllint
|
yamllint
|
||||||
pip>=25.3 # PEP 660 – Editable installs for pyproject.toml based builds (wheel based)
|
pip>=25.3 # PEP 660 – Editable installs for pyproject.toml based builds (wheel based)
|
||||||
awx-tui
|
awx-tui
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ RUN dnf module -y enable nodejs:18 && dnf module -y install nodejs:18/common &&
|
|||||||
unzip
|
unzip
|
||||||
|
|
||||||
RUN pip3.12 install -vv git+https://github.com/coderanger/supervisor-stdout.git@973ba19967cdaf46d9c1634d1675fc65b9574f6e
|
RUN pip3.12 install -vv git+https://github.com/coderanger/supervisor-stdout.git@973ba19967cdaf46d9c1634d1675fc65b9574f6e
|
||||||
RUN pip3.12 install -vv black setuptools-scm build
|
RUN pip3.12 install -vv ruff setuptools-scm build
|
||||||
|
|
||||||
# This package randomly fails to download.
|
# This package randomly fails to download.
|
||||||
# It is nice to have in the dev env, but not necessary.
|
# It is nice to have in the dev env, but not necessary.
|
||||||
|
|||||||
@@ -3,22 +3,17 @@ isolated_build = True
|
|||||||
|
|
||||||
[testenv:linters]
|
[testenv:linters]
|
||||||
deps =
|
deps =
|
||||||
black
|
ruff
|
||||||
flake8
|
|
||||||
yamllint
|
yamllint
|
||||||
allowlist_externals = make
|
allowlist_externals = make
|
||||||
setenv =
|
setenv =
|
||||||
BLACK_ARGS = --check
|
|
||||||
PYTHON = python3
|
PYTHON = python3
|
||||||
commands =
|
commands =
|
||||||
make black
|
# awx_collection is excluded: ansible-test sanity runs its own linters which conflict with ruff
|
||||||
flake8 awx awxkit awx_collection
|
ruff format --check awx awxkit
|
||||||
|
ruff check awx awxkit
|
||||||
yamllint -s .
|
yamllint -s .
|
||||||
|
|
||||||
[flake8]
|
|
||||||
select = F401,F402,F821,F823,F841,F811,E265,E266,F541,W605,E722,F822,F523,W291,F405
|
|
||||||
exclude = env,awx_collection_build,.tox
|
|
||||||
|
|
||||||
[testenv:pip-compile-docs]
|
[testenv:pip-compile-docs]
|
||||||
description = Compile docs build lockfiles
|
description = Compile docs build lockfiles
|
||||||
deps =
|
deps =
|
||||||
|
|||||||
Reference in New Issue
Block a user