Skip to content

Commit 303ea38

Browse files
committed
fix: refactor RulesCollection to always require app argument
This change reduce use of get_app in codebase as this can cause unexpected behaviors for tests and also at runtime. Related: AAP-60425
1 parent 4726972 commit 303ea38

19 files changed

+96
-43
lines changed

.config/requirements-lock.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This file was autogenerated by uv via the following command:
2-
# uv export --no-dev --no-emit-package ansible-core --no-emit-package resolvelib --no-emit-package ruamel-yaml-clib --no-emit-package tomli --no-emit-package typing-extensions --no-emit-project --no-hashes -o .config/requirements-lock.txt
2+
# uv export --no-default-groups --no-dev --no-emit-package ansible-core --no-emit-package resolvelib --no-emit-package ruamel-yaml-clib --no-emit-package tomli --no-emit-package typing-extensions --no-emit-project --no-hashes -o .config/requirements-lock.txt
33
ansible-compat==25.12.0
44
# via ansible-lint
55
attrs==25.4.0

.pre-commit-config.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ repos:
3030
hooks:
3131
- id: check-useless-excludes
3232
- repo: https://github.com/astral-sh/uv-pre-commit
33-
rev: 0.9.21
33+
rev: 0.9.22
3434
hooks:
3535
- id: uv-sync
3636
- id: uv-lock
@@ -42,6 +42,7 @@ repos:
4242
- id: uv-export
4343
name: "deps: regenerate requirements-lock.txt for actions"
4444
args:
45+
- "--no-default-groups"
4546
- "--no-dev"
4647
- "--no-emit-package"
4748
- ansible-core
@@ -146,7 +147,7 @@ repos:
146147
entry: yamllint --strict
147148

148149
- repo: https://github.com/tombi-toml/tombi-pre-commit
149-
rev: v0.7.14
150+
rev: v0.7.15
150151
hooks:
151152
- id: tombi-format
152153
alias: toml
@@ -160,6 +161,7 @@ repos:
160161
alias: ruff
161162
- id: ruff-check
162163
alias: ruff
164+
args: ["--unsafe-fixes"]
163165
- repo: https://github.com/pre-commit/mirrors-mypy
164166
rev: v1.19.1
165167
hooks:

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ lint = [
103103
"pre-commit>=4.1",
104104
"pre-commit-uv>=4.1.4",
105105
"pytest>=9",
106+
"ruff>=0.14.10",
106107
"setuptools>=51.1.1",
107108
]
108109
pkg = [
@@ -873,6 +874,7 @@ PRE_COMMIT_COLOR = "always"
873874

874875
[tool.uv]
875876
package = true
877+
default-groups = "all"
876878

877879
[tool.vulture]
878880
exclude = [

src/ansiblelint/__main__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,9 +376,9 @@ def main(argv: list[str] | None = None) -> int:
376376
cached=True,
377377
) # to be sure we use the offline value from settings
378378
rules = RulesCollection(
379-
options.rulesdirs,
380-
profile_name=options.profile,
381379
app=app,
380+
rulesdirs=options.rulesdirs,
381+
profile_name=options.profile,
382382
options=options,
383383
)
384384

src/ansiblelint/app.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import logging
88
import os
99
import sys
10-
from functools import lru_cache
1110
from pathlib import Path
1211
from typing import TYPE_CHECKING, Any
1312

@@ -387,7 +386,6 @@ def _sanitize_list_options(tag_list: list[str]) -> list[str]:
387386
return sorted(set(tags))
388387

389388

390-
@lru_cache
391389
def get_app(*, offline: bool | None = None, cached: bool = False) -> App:
392390
"""Return the application instance, caching the return value."""
393391
# Avoids ever running the app initialization twice if cached argument

src/ansiblelint/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,11 @@ def get_version_warning() -> str:
314314
release_url = (
315315
"https://api.github.com/repos/ansible/ansible-lint/releases/latest"
316316
)
317+
if not release_url.startswith(
318+
"https://"
319+
): # pragma: no cover (ruff compatibility)
320+
msg = "release_url must start with https://"
321+
raise ValueError(msg)
317322
try:
318323
with urllib.request.urlopen(release_url) as url:
319324
data = json.load(url)

src/ansiblelint/rules/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
RuntimeErrorRule,
2424
WarningRule,
2525
)
26-
from ansiblelint.app import App, get_app
2726
from ansiblelint.config import PROFILES, Options
2827
from ansiblelint.config import options as default_options
2928
from ansiblelint.constants import RULE_DOC_URL, SKIPPED_RULES_KEY
@@ -33,6 +32,7 @@
3332
if TYPE_CHECKING:
3433
from ruamel.yaml.comments import CommentedMap, CommentedSeq
3534

35+
from ansiblelint.app import App
3636
from ansiblelint.errors import RuleMatchTransformMeta
3737

3838
_logger = logging.getLogger(__name__)
@@ -390,12 +390,12 @@ class RulesCollection:
390390

391391
def __init__( # pylint: disable=too-many-arguments
392392
self,
393+
app: App,
393394
rulesdirs: list[str] | list[Path] | None = None,
394395
options: Options | None = None,
395396
profile_name: str | None = None,
396397
*,
397398
conditional: bool = True,
398-
app: App | None = None,
399399
) -> None:
400400
"""Initialize a RulesCollection instance."""
401401
if options is None:
@@ -406,10 +406,7 @@ def __init__( # pylint: disable=too-many-arguments
406406
else:
407407
self.options = options
408408
self.profile = []
409-
# app should be defined on normal run logic, but for testing we might
410-
# not pass it, and in this case we assume offline mode for performance
411-
# reasons.
412-
self.app = app or get_app(offline=True)
409+
self.app = app
413410

414411
if profile_name:
415412
self.profile = PROFILES[profile_name]

src/ansiblelint/rules/complexity.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from ansiblelint.rules import AnsibleLintRule, RulesCollection
1010

1111
if TYPE_CHECKING:
12+
from ansiblelint.app import App
1213
from ansiblelint.config import Options
1314
from ansiblelint.errors import MatchError
1415
from ansiblelint.file_utils import Lintable
@@ -100,11 +101,12 @@ def test_complexity(
100101
expected_results: list[str],
101102
monkeypatch: pytest.MonkeyPatch,
102103
config_options: Options,
104+
app: App,
103105
) -> None:
104106
"""Test rule."""
105107
monkeypatch.setattr(config_options, "max_tasks", 5)
106108
monkeypatch.setattr(config_options, "max_block_depth", 3)
107-
collection = RulesCollection(options=config_options)
109+
collection = RulesCollection(app=app, options=config_options)
108110
collection.register(ComplexityRule())
109111
results = Runner(file, rules=collection).run()
110112

src/ansiblelint/rules/name.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
if TYPE_CHECKING:
1616
from ruamel.yaml.comments import CommentedMap, CommentedSeq
1717

18+
from ansiblelint.app import App
1819
from ansiblelint.config import Options
1920
from ansiblelint.errors import MatchError
2021
from ansiblelint.utils import Task
@@ -324,10 +325,10 @@ def test_file_negative(empty_rule_collection: RulesCollection) -> None:
324325
errs = bad_runner.run()
325326
assert len(errs) == 5
326327

327-
def test_name_prefix_positive(config_options: Options) -> None:
328+
def test_name_prefix_positive(config_options: Options, app: App) -> None:
328329
"""Positive test for name[prefix]."""
329330
config_options.enable_list = ["name[prefix]"]
330-
collection = RulesCollection(options=config_options)
331+
collection = RulesCollection(app=app, options=config_options)
331332
collection.register(NameRule())
332333
success = Lintable(
333334
"examples/playbooks/tasks/main.yml",
@@ -337,10 +338,10 @@ def test_name_prefix_positive(config_options: Options) -> None:
337338
results = good_runner.run()
338339
assert len(results) == 0
339340

340-
def test_name_prefix_negative(config_options: Options) -> None:
341+
def test_name_prefix_negative(config_options: Options, app: App) -> None:
341342
"""Negative test for name[missing]."""
342343
config_options.enable_list = ["name[prefix]"]
343-
collection = RulesCollection(options=config_options)
344+
collection = RulesCollection(app=app, options=config_options)
344345
collection.register(NameRule())
345346
failure = Lintable(
346347
"examples/playbooks/tasks/rule-name-prefix-fail.yml",
@@ -354,10 +355,10 @@ def test_name_prefix_negative(config_options: Options) -> None:
354355
assert results[1].tag == "name[prefix]"
355356
assert results[2].tag == "name[prefix]"
356357

357-
def test_name_prefix_negative_2(config_options: Options) -> None:
358+
def test_name_prefix_negative_2(config_options: Options, app: App) -> None:
358359
"""Negative test for name[prefix]."""
359360
config_options.enable_list = ["name[prefix]"]
360-
collection = RulesCollection(options=config_options)
361+
collection = RulesCollection(app=app, options=config_options)
361362
collection.register(NameRule())
362363
failure = Lintable(
363364
"examples/playbooks/tasks/partial_prefix/foo.yml",
@@ -369,10 +370,10 @@ def test_name_prefix_negative_2(config_options: Options) -> None:
369370
assert results[0].tag == "name[prefix]"
370371
assert results[1].tag == "name[prefix]"
371372

372-
def test_name_prefix_negative_3(config_options: Options) -> None:
373+
def test_name_prefix_negative_3(config_options: Options, app: App) -> None:
373374
"""Negative test for name[prefix]."""
374375
config_options.enable_list = ["name[prefix]"]
375-
collection = RulesCollection(options=config_options)
376+
collection = RulesCollection(app=app, options=config_options)
376377
collection.register(NameRule())
377378
failure = Lintable(
378379
"examples/playbooks/tasks/partial_prefix/main.yml",

src/ansiblelint/rules/no_log_password.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
if TYPE_CHECKING:
3030
from ruamel.yaml.comments import CommentedMap, CommentedSeq
3131

32+
from ansiblelint.app import App
3233
from ansiblelint.config import Options
3334
from ansiblelint.errors import MatchError
3435
from ansiblelint.file_utils import Lintable
@@ -332,11 +333,12 @@ def test_password_lock_false(rule_runner: RunFromText) -> None:
332333
@mock.patch.dict(os.environ, {"ANSIBLE_LINT_WRITE_TMP": "1"}, clear=True)
333334
def test_no_log_password_transform(
334335
config_options: Options,
336+
app: App,
335337
) -> None:
336338
"""Test transform functionality for no-log-password rule."""
337339
playbook = Path("examples/playbooks/transform-no-log-password.yml")
338340
config_options.write_list = ["all"]
339-
rules = RulesCollection(options=config_options)
341+
rules = RulesCollection(app=app, options=config_options)
340342
rules.register(NoLogPasswordsRule())
341343

342344
config_options.lintables = [str(playbook)]

0 commit comments

Comments
 (0)