antsibull-nox 0.2.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,113 @@
1
+ # Author: Felix Fontein <felix@fontein.de>
2
+ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
3
+ # https://www.gnu.org/licenses/gpl-3.0.txt)
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ # SPDX-FileCopyrightText: 2025, Ansible Project
6
+
7
+ """Lint antsibull-nox config."""
8
+
9
+ from __future__ import annotations
10
+
11
+ import ast
12
+ from pathlib import Path
13
+
14
+ from .config import lint_config_toml
15
+
16
+ NOXFILE_PY = "noxfile.py"
17
+
18
+
19
+ def _is_antsibull_nox_module(module_name: str) -> bool:
20
+ return module_name == "antsibull_nox" or module_name.startswith("antsibull_nox.")
21
+
22
+
23
+ class _Walker:
24
+ def __init__(self, path: Path) -> None:
25
+ self.path = path
26
+ self.imports: dict[str, str] = {}
27
+ self.has_config_load = False
28
+
29
+ @staticmethod
30
+ def _get_name(what: ast.expr) -> str | None:
31
+ if isinstance(what, ast.Name):
32
+ return what.id
33
+ if isinstance(what, ast.Attribute):
34
+ v = _Walker._get_name(what.value)
35
+ return None if v is None else f"{v}.{what.attr}"
36
+ return None
37
+
38
+ def _check_expression(self, expression: ast.expr) -> None:
39
+ if isinstance(expression, ast.Call):
40
+ func = _Walker._get_name(expression.func)
41
+ if func is not None:
42
+ func = self.imports.get(func, func)
43
+ if "." in func:
44
+ module, module_func = func.rsplit(".", 1)
45
+ if module in self.imports:
46
+ func = f"{self.imports[module]}.{module_func}"
47
+ if func == "antsibull_nox.load_antsibull_nox_toml":
48
+ self.has_config_load = True
49
+
50
+ def _walk(self, statements: list[ast.stmt]) -> None:
51
+ for statement in statements:
52
+ # Handle imports
53
+ if isinstance(statement, ast.Import):
54
+ for alias in statement.names:
55
+ if _is_antsibull_nox_module(alias.name):
56
+ self.imports[alias.asname or alias.name] = alias.name
57
+ if isinstance(statement, ast.ImportFrom):
58
+ if statement.level == 0 and _is_antsibull_nox_module(
59
+ statement.module or ""
60
+ ):
61
+ for alias in statement.names:
62
+ self.imports[alias.asname or alias.name] = (
63
+ f"{statement.module}.{alias.name}"
64
+ )
65
+ # Handle try block
66
+ if isinstance(statement, ast.Try):
67
+ self._walk(statement.body)
68
+ # Handle expressions
69
+ if isinstance(statement, ast.Expr):
70
+ self._check_expression(statement.value)
71
+
72
+ def walk(self, module: ast.Module) -> list[str]:
73
+ """
74
+ Walk the noxfile's module and return a list of errors.
75
+ """
76
+ self._walk(module.body)
77
+ errors = []
78
+ if not self.imports:
79
+ errors.append(f"{self.path}: Found no antsibull_nox import")
80
+ if not self.has_config_load:
81
+ errors.append(
82
+ f"{self.path}: Found no call to antsibull_nox.load_antsibull_nox_toml()"
83
+ )
84
+ return errors
85
+
86
+
87
+ def lint_noxfile() -> list[str]:
88
+ """
89
+ Do basic validation for noxfile.py. Return a list of errors.
90
+ """
91
+ path = Path(NOXFILE_PY)
92
+ try:
93
+ with open(path, "rt", encoding="utf-8") as f:
94
+ root = ast.parse(f.read(), filename=path)
95
+ except FileNotFoundError:
96
+ return [f"{path}: File does not exist"]
97
+ except Exception as exc: # pylint: disable=broad-exception-caught
98
+ return [f"{path}:Error while parsing Python code: {exc}"]
99
+
100
+ walker = _Walker(path)
101
+ return walker.walk(root)
102
+
103
+
104
+ def lint_config() -> list[str]:
105
+ """
106
+ Lint antsibull-nox config file.
107
+ """
108
+ errors = lint_config_toml()
109
+ errors.extend(lint_noxfile())
110
+ return sorted(errors)
111
+
112
+
113
+ __all__ = ["lint_config"]
@@ -0,0 +1,70 @@
1
+ # Author: Felix Fontein <felix@fontein.de>
2
+ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
3
+ # https://www.gnu.org/licenses/gpl-3.0.txt)
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ # SPDX-FileCopyrightText: 2025, Ansible Project
6
+
7
+ """
8
+ Create nox sessions.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ import os
15
+ import sys
16
+
17
+ import nox
18
+
19
+ from .collections import ( # Re-export for usage in noxfiles
20
+ CollectionSetup,
21
+ prepare_collections,
22
+ )
23
+ from .utils import get_registered_sessions
24
+
25
+
26
+ def add_matrix_generator() -> None:
27
+ """
28
+ Add a session that generates matrixes for CI systems.
29
+ """
30
+
31
+ def matrix_generator(
32
+ session: nox.Session, # pylint: disable=unused-argument
33
+ ) -> None:
34
+ registered_sessions = get_registered_sessions()
35
+
36
+ json_output = os.environ.get("ANTSIBULL_NOX_MATRIX_JSON")
37
+ if json_output:
38
+ print(f"Writing JSON output to {json_output}...")
39
+ with open(json_output, "wt", encoding="utf-8") as f:
40
+ f.write(json.dumps(registered_sessions))
41
+
42
+ github_output = os.environ.get("GITHUB_OUTPUT")
43
+ if github_output:
44
+ print(f"Writing GitHub output to {github_output}...")
45
+ with open(github_output, "at", encoding="utf-8") as f:
46
+ for name, sessions in registered_sessions.items():
47
+ f.write(f"{name}={json.dumps(sessions)}\n")
48
+
49
+ for name, sessions in sorted(registered_sessions.items()):
50
+ print(f"{name} ({len(sessions)}):")
51
+ for session_data in sessions:
52
+ data = session_data.copy()
53
+ session_name = data.pop("name")
54
+ print(f" {session_name}: {data}")
55
+
56
+ sys.stdout.flush()
57
+
58
+ matrix_generator.__doc__ = "Generate matrix for CI systems."
59
+ nox.session(
60
+ name="matrix-generator",
61
+ python=False,
62
+ default=False,
63
+ )(matrix_generator)
64
+
65
+
66
+ __all__ = [
67
+ "CollectionSetup",
68
+ "add_matrix_generator",
69
+ "prepare_collections",
70
+ ]
@@ -0,0 +1,58 @@
1
+ # Author: Felix Fontein <felix@fontein.de>
2
+ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
3
+ # https://www.gnu.org/licenses/gpl-3.0.txt)
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ # SPDX-FileCopyrightText: 2025, Ansible Project
6
+
7
+ """
8
+ Create nox ansible-lint session.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import nox
14
+
15
+ from .collections import prepare_collections
16
+ from .utils import install
17
+
18
+
19
+ def add_ansible_lint(
20
+ *,
21
+ make_ansible_lint_default: bool = True,
22
+ ansible_lint_package: str = "ansible-lint",
23
+ strict: bool = False,
24
+ ) -> None:
25
+ """
26
+ Add a session that runs ansible-lint.
27
+ """
28
+
29
+ def compose_dependencies() -> list[str]:
30
+ return [ansible_lint_package]
31
+
32
+ def ansible_lint(session: nox.Session) -> None:
33
+ install(session, *compose_dependencies())
34
+ prepared_collections = prepare_collections(
35
+ session,
36
+ install_in_site_packages=False,
37
+ install_out_of_tree=True,
38
+ extra_deps_files=["tests/integration/requirements.yml"],
39
+ )
40
+ if not prepared_collections:
41
+ session.warn("Skipping ansible-lint...")
42
+ return
43
+ env = {"ANSIBLE_COLLECTIONS_PATH": f"{prepared_collections.current_place}"}
44
+ command = ["ansible-lint", "--offline"]
45
+ if strict:
46
+ command.append("--strict")
47
+ session.run(*command, env=env)
48
+
49
+ ansible_lint.__doc__ = "Run ansible-lint."
50
+ nox.session(
51
+ name="ansible-lint",
52
+ default=make_ansible_lint_default,
53
+ )(ansible_lint)
54
+
55
+
56
+ __all__ = [
57
+ "add_ansible_lint",
58
+ ]