diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index a8b7328c5d..581d05a0ba 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -70,7 +70,7 @@ jobs: env: # Number of expected test passes, safety measure for accidental skip of # tests. Update value if you add/remove tests. - PYTEST_REQPASS: 845 + PYTEST_REQPASS: 847 steps: - uses: actions/checkout@v4 with: diff --git a/examples/playbooks/nodeps.yml b/examples/playbooks/nodeps.yml new file mode 100644 index 0000000000..0ca1aa3a13 --- /dev/null +++ b/examples/playbooks/nodeps.yml @@ -0,0 +1,6 @@ +--- +- name: Example + hosts: localhost + tasks: + - name: Calling a module that is not installed + a.b.c: {} diff --git a/examples/playbooks/nodeps2.yml b/examples/playbooks/nodeps2.yml new file mode 100644 index 0000000000..fc784d0220 --- /dev/null +++ b/examples/playbooks/nodeps2.yml @@ -0,0 +1,7 @@ +--- +- name: Fixture for nodeps with missing filter + hosts: localhost + tasks: + - name: Calling a module that is not installed + ansible.builtin.debug: + msg: "{{ foo | missing_filter }}" diff --git a/src/ansiblelint/__main__.py b/src/ansiblelint/__main__.py index 019838f1cd..938ca525df 100755 --- a/src/ansiblelint/__main__.py +++ b/src/ansiblelint/__main__.py @@ -318,6 +318,7 @@ def main(argv: list[str] | None = None) -> int: ), ) or options.offline + or options.nodeps ) if not skip_schema_update: diff --git a/src/ansiblelint/config.py b/src/ansiblelint/config.py index 9be22824af..467d9e4f3b 100644 --- a/src/ansiblelint/config.py +++ b/src/ansiblelint/config.py @@ -173,6 +173,12 @@ class Options: # pylint: disable=too-many-instance-attributes ignore_file: Path | None = None max_tasks: int = 100 max_block_depth: int = 20 + nodeps: bool = bool(int(os.environ.get("ANSIBLE_LINT_NODEPS", "0"))) + + def __post_init__(self) -> None: + """Extra initialization logic.""" + if self.nodeps: + self.offline = True options = Options() diff --git a/src/ansiblelint/constants.py b/src/ansiblelint/constants.py index ad051ba47f..e9b44c37c6 100644 --- a/src/ansiblelint/constants.py +++ b/src/ansiblelint/constants.py @@ -13,6 +13,7 @@ "ANSIBLE_LINT_IGNORE_FILE": "Define it to override the name of the default ignore file `.ansible-lint-ignore`", "ANSIBLE_LINT_WRITE_TMP": "Tells linter to dump fixes into different temp files instead of overriding original. Used internally for testing.", SKIP_SCHEMA_UPDATE: "Tells ansible-lint to skip schema refresh.", + "ANSIBLE_LINT_NODEPS": "Avoids installing content dependencies and avoids performing checks that would fail when modules are not installed. Far less violations will be reported.", } EPILOG = ( diff --git a/src/ansiblelint/rules/syntax_check.md b/src/ansiblelint/rules/syntax_check.md index e8197a5c60..659e3afab3 100644 --- a/src/ansiblelint/rules/syntax_check.md +++ b/src/ansiblelint/rules/syntax_check.md @@ -9,7 +9,7 @@ You can exclude these files from linting, but it is better to make sure they can be loaded by Ansible. This is often achieved by editing the inventory file and/or `ansible.cfg` so ansible can load required variables. -If undefined variables cause the failure, you can use the jinja `default()` +If undefined variables cause the failure, you can use the Jinja `default()` filter to provide fallback values, like in the example below. This rule is among the few `unskippable` rules that cannot be added to @@ -20,9 +20,13 @@ fixtures that are invalid on purpose. One of the most common sources of errors is a failure to assert the presence of various variables at the beginning of the playbook. -This rule can produce messages like below: +This rule can produce messages like: -- `syntax-check[empty-playbook]` is raised when a playbook file has no content. +- `syntax-check[empty-playbook]`: Empty playbook, nothing to do +- `syntax-check[malformed]`: A malformed block was encountered while loading a block +- `syntax-check[missing-file]`: Unable to retrieve file contents ... Could not find or access ... +- `syntax-check[unknown-module]`: couldn't resolve module/action +- `syntax-check[specific]`: for other errors not mentioned above. ## Problematic code diff --git a/src/ansiblelint/rules/syntax_check.py b/src/ansiblelint/rules/syntax_check.py index c6a4c5efb5..2b5b65b850 100644 --- a/src/ansiblelint/rules/syntax_check.py +++ b/src/ansiblelint/rules/syntax_check.py @@ -15,6 +15,8 @@ class KnownError: regex: re.Pattern[str] +# Order matters, we only report the first matching pattern, the one at the end +# is used to match generic or less specific patterns. OUTPUT_PATTERNS = ( KnownError( tag="missing-file", @@ -25,23 +27,30 @@ class KnownError: ), ), KnownError( - tag="specific", + tag="empty-playbook", regex=re.compile( - r"^ERROR! (?P