antsibull-nox 0.1.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.
- antsibull_nox/__init__.py +17 -14
- antsibull_nox/_pydantic.py +98 -0
- antsibull_nox/ansible.py +260 -0
- antsibull_nox/cli.py +132 -0
- antsibull_nox/collection/__init__.py +56 -0
- antsibull_nox/collection/data.py +106 -0
- antsibull_nox/collection/extract.py +23 -0
- antsibull_nox/collection/install.py +523 -0
- antsibull_nox/collection/search.py +460 -0
- antsibull_nox/config.py +378 -0
- antsibull_nox/data/action-groups.py +3 -3
- antsibull_nox/data/antsibull-nox-lint-config.py +29 -0
- antsibull_nox/data/antsibull_nox_data_util.py +91 -0
- antsibull_nox/data/license-check.py +6 -2
- antsibull_nox/data/no-unwanted-files.py +5 -1
- antsibull_nox/data/plugin-yamllint.py +247 -0
- antsibull_nox/data_util.py +0 -77
- antsibull_nox/init.py +83 -0
- antsibull_nox/interpret_config.py +244 -0
- antsibull_nox/lint_config.py +113 -0
- antsibull_nox/paths.py +19 -0
- antsibull_nox/python.py +81 -0
- antsibull_nox/sessions/__init__.py +70 -0
- antsibull_nox/sessions/ansible_lint.py +58 -0
- antsibull_nox/sessions/ansible_test.py +568 -0
- antsibull_nox/sessions/build_import_check.py +147 -0
- antsibull_nox/sessions/collections.py +137 -0
- antsibull_nox/sessions/docs_check.py +78 -0
- antsibull_nox/sessions/extra_checks.py +127 -0
- antsibull_nox/sessions/license_check.py +73 -0
- antsibull_nox/sessions/lint.py +627 -0
- antsibull_nox/sessions/utils.py +206 -0
- antsibull_nox/utils.py +85 -0
- {antsibull_nox-0.1.0.dist-info → antsibull_nox-0.3.0.dist-info}/METADATA +4 -2
- antsibull_nox-0.3.0.dist-info/RECORD +40 -0
- antsibull_nox-0.3.0.dist-info/entry_points.txt +2 -0
- antsibull_nox/collection.py +0 -545
- antsibull_nox/sessions.py +0 -840
- antsibull_nox-0.1.0.dist-info/RECORD +0 -14
- {antsibull_nox-0.1.0.dist-info → antsibull_nox-0.3.0.dist-info}/WHEEL +0 -0
- {antsibull_nox-0.1.0.dist-info → antsibull_nox-0.3.0.dist-info}/licenses/LICENSES/GPL-3.0-or-later.txt +0 -0
antsibull_nox/sessions.py
DELETED
@@ -1,840 +0,0 @@
|
|
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 os
|
14
|
-
import shlex
|
15
|
-
import subprocess
|
16
|
-
import sys
|
17
|
-
import typing as t
|
18
|
-
from dataclasses import asdict, dataclass
|
19
|
-
from pathlib import Path
|
20
|
-
|
21
|
-
import nox
|
22
|
-
|
23
|
-
from .collection import (
|
24
|
-
CollectionData,
|
25
|
-
force_collection_version,
|
26
|
-
load_collection_data_from_disk,
|
27
|
-
setup_collections,
|
28
|
-
setup_current_tree,
|
29
|
-
)
|
30
|
-
from .data_util import prepare_data_script
|
31
|
-
from .paths import (
|
32
|
-
copy_collection,
|
33
|
-
create_temp_directory,
|
34
|
-
filter_paths,
|
35
|
-
find_data_directory,
|
36
|
-
list_all_files,
|
37
|
-
remove_path,
|
38
|
-
)
|
39
|
-
|
40
|
-
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables
|
41
|
-
# https://docs.gitlab.com/ci/variables/predefined_variables/#predefined-variables
|
42
|
-
# https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
|
43
|
-
IN_CI = os.environ.get("CI") == "true"
|
44
|
-
ALLOW_EDITABLE = os.environ.get("ALLOW_EDITABLE", str(not IN_CI)).lower() in (
|
45
|
-
"1",
|
46
|
-
"true",
|
47
|
-
)
|
48
|
-
|
49
|
-
COLLECTION_NAME = "community.dns"
|
50
|
-
|
51
|
-
CODE_FILES = [
|
52
|
-
"plugins",
|
53
|
-
"tests/unit",
|
54
|
-
]
|
55
|
-
|
56
|
-
MODULE_PATHS = [
|
57
|
-
"plugins/modules/",
|
58
|
-
"plugins/module_utils/",
|
59
|
-
"tests/unit/plugins/modules/",
|
60
|
-
"tests/unit/plugins/module_utils/",
|
61
|
-
]
|
62
|
-
|
63
|
-
|
64
|
-
def install(session: nox.Session, *args: str, editable: bool = False, **kwargs):
|
65
|
-
"""
|
66
|
-
Install Python packages.
|
67
|
-
"""
|
68
|
-
# nox --no-venv
|
69
|
-
if isinstance(session.virtualenv, nox.virtualenv.PassthroughEnv):
|
70
|
-
session.warn(f"No venv. Skipping installation of {args}")
|
71
|
-
return
|
72
|
-
# Don't install in editable mode in CI or if it's explicitly disabled.
|
73
|
-
# This ensures that the wheel contains all of the correct files.
|
74
|
-
if editable and ALLOW_EDITABLE:
|
75
|
-
args = ("-e", *args)
|
76
|
-
session.install(*args, "-U", **kwargs)
|
77
|
-
|
78
|
-
|
79
|
-
@dataclass
|
80
|
-
class CollectionSetup:
|
81
|
-
"""
|
82
|
-
Information on the setup collections.
|
83
|
-
"""
|
84
|
-
|
85
|
-
# The path of the ansible_collections directory where all dependent collections
|
86
|
-
# are installed. Is currently identical to current_root, but that might change
|
87
|
-
# or depend on options in the future.
|
88
|
-
collections_root: Path
|
89
|
-
|
90
|
-
# The directory in which ansible_collections can be found, as well as
|
91
|
-
# ansible_collections/<namespace>/<name> points to a copy of the current collection.
|
92
|
-
current_place: Path
|
93
|
-
|
94
|
-
# The path of the ansible_collections directory that contains the current collection.
|
95
|
-
# The following is always true:
|
96
|
-
# current_root == current_place / "ansible_collections"
|
97
|
-
current_root: Path
|
98
|
-
|
99
|
-
# Data on the current collection (as in the repository).
|
100
|
-
current_collection: CollectionData
|
101
|
-
|
102
|
-
# The path of the current collection inside the collection tree below current_root.
|
103
|
-
# The following is always true:
|
104
|
-
# current_path == current_root / current_collection.namespace / current_collection.name
|
105
|
-
current_path: Path
|
106
|
-
|
107
|
-
def prefix_current_paths(self, paths: list[str]) -> list[str]:
|
108
|
-
"""
|
109
|
-
Prefix the list of given paths with ``current_path``.
|
110
|
-
"""
|
111
|
-
result = []
|
112
|
-
for path in paths:
|
113
|
-
prefixed_path = (self.current_path / path).relative_to(self.current_place)
|
114
|
-
if prefixed_path.exists():
|
115
|
-
result.append(str(prefixed_path))
|
116
|
-
return result
|
117
|
-
|
118
|
-
|
119
|
-
def _run_subprocess(args: list[str]) -> tuple[bytes, bytes]:
|
120
|
-
p = subprocess.run(args, check=True, capture_output=True)
|
121
|
-
return p.stdout, p.stderr
|
122
|
-
|
123
|
-
|
124
|
-
def prepare_collections(
|
125
|
-
session: nox.Session,
|
126
|
-
*,
|
127
|
-
install_in_site_packages: bool,
|
128
|
-
extra_deps_files: list[str | os.PathLike] | None = None,
|
129
|
-
extra_collections: list[str] | None = None,
|
130
|
-
install_out_of_tree: bool = False, # can not be used with install_in_site_packages=True
|
131
|
-
) -> CollectionSetup | None:
|
132
|
-
"""
|
133
|
-
Install collections in site-packages.
|
134
|
-
"""
|
135
|
-
if install_out_of_tree and install_in_site_packages:
|
136
|
-
raise ValueError(
|
137
|
-
"install_out_of_tree=True cannot be combined with install_in_site_packages=True"
|
138
|
-
)
|
139
|
-
if isinstance(session.virtualenv, nox.virtualenv.PassthroughEnv):
|
140
|
-
session.warn("No venv. Skip preparing collections...")
|
141
|
-
return None
|
142
|
-
if install_in_site_packages:
|
143
|
-
purelib = (
|
144
|
-
session.run(
|
145
|
-
"python",
|
146
|
-
"-c",
|
147
|
-
"import sysconfig; print(sysconfig.get_path('purelib'))",
|
148
|
-
silent=True,
|
149
|
-
)
|
150
|
-
or ""
|
151
|
-
).strip()
|
152
|
-
if not purelib:
|
153
|
-
session.warn(
|
154
|
-
"Cannot find site-packages (probably due to install-only run)."
|
155
|
-
" Skip preparing collections..."
|
156
|
-
)
|
157
|
-
return None
|
158
|
-
place = Path(purelib)
|
159
|
-
elif install_out_of_tree:
|
160
|
-
place = create_temp_directory(f"antsibull-nox-{session.name}-collection-root-")
|
161
|
-
else:
|
162
|
-
place = Path(session.virtualenv.location) / "collection-root"
|
163
|
-
place.mkdir(exist_ok=True)
|
164
|
-
setup = setup_collections(
|
165
|
-
place,
|
166
|
-
_run_subprocess,
|
167
|
-
extra_deps_files=extra_deps_files,
|
168
|
-
extra_collections=extra_collections,
|
169
|
-
with_current=False,
|
170
|
-
)
|
171
|
-
current_setup = setup_current_tree(place, setup.current_collection)
|
172
|
-
return CollectionSetup(
|
173
|
-
collections_root=setup.root,
|
174
|
-
current_place=place,
|
175
|
-
current_root=current_setup.root,
|
176
|
-
current_collection=setup.current_collection,
|
177
|
-
current_path=t.cast(Path, current_setup.current_path),
|
178
|
-
)
|
179
|
-
|
180
|
-
|
181
|
-
def _run_bare_script(
|
182
|
-
session: nox.Session, /, name: str, *, extra_data: dict[str, t.Any] | None = None
|
183
|
-
) -> None:
|
184
|
-
files = list_all_files()
|
185
|
-
data = prepare_data_script(
|
186
|
-
session,
|
187
|
-
base_name=name,
|
188
|
-
paths=files,
|
189
|
-
extra_data=extra_data,
|
190
|
-
)
|
191
|
-
session.run(
|
192
|
-
sys.executable,
|
193
|
-
find_data_directory() / f"{name}.py",
|
194
|
-
"--data",
|
195
|
-
data,
|
196
|
-
external=True,
|
197
|
-
)
|
198
|
-
|
199
|
-
|
200
|
-
def add_lint(
|
201
|
-
*, make_lint_default: bool, has_formatters: bool, has_codeqa: bool, has_typing: bool
|
202
|
-
) -> None:
|
203
|
-
"""
|
204
|
-
Add nox meta session for linting.
|
205
|
-
"""
|
206
|
-
|
207
|
-
def lint(session: nox.Session) -> None: # pylint: disable=unused-argument
|
208
|
-
pass # this session is deliberately empty
|
209
|
-
|
210
|
-
dependent_sessions = []
|
211
|
-
if has_formatters:
|
212
|
-
dependent_sessions.append("formatters")
|
213
|
-
if has_codeqa:
|
214
|
-
dependent_sessions.append("codeqa")
|
215
|
-
if has_typing:
|
216
|
-
dependent_sessions.append("typing")
|
217
|
-
nox.session( # type: ignore
|
218
|
-
lint, name="lint", default=make_lint_default, requires=dependent_sessions
|
219
|
-
)
|
220
|
-
|
221
|
-
|
222
|
-
def add_formatters(
|
223
|
-
*,
|
224
|
-
extra_code_files: list[str],
|
225
|
-
# isort:
|
226
|
-
run_isort: bool,
|
227
|
-
isort_config: str | os.PathLike | None,
|
228
|
-
isort_package: str,
|
229
|
-
# black:
|
230
|
-
run_black: bool,
|
231
|
-
run_black_modules: bool | None,
|
232
|
-
black_config: str | os.PathLike | None,
|
233
|
-
black_package: str,
|
234
|
-
) -> None:
|
235
|
-
"""
|
236
|
-
Add nox session for formatters.
|
237
|
-
"""
|
238
|
-
if run_black_modules is None:
|
239
|
-
run_black_modules = run_black
|
240
|
-
run_check = IN_CI
|
241
|
-
|
242
|
-
def compose_dependencies() -> list[str]:
|
243
|
-
deps = []
|
244
|
-
if run_isort:
|
245
|
-
deps.append(isort_package)
|
246
|
-
if run_black or run_black_modules:
|
247
|
-
deps.append(black_package)
|
248
|
-
return deps
|
249
|
-
|
250
|
-
def execute_isort(session: nox.Session) -> None:
|
251
|
-
command: list[str] = [
|
252
|
-
"isort",
|
253
|
-
]
|
254
|
-
if run_check:
|
255
|
-
command.append("--check")
|
256
|
-
if isort_config is not None:
|
257
|
-
command.extend(["--settings-file", str(isort_config)])
|
258
|
-
command.extend(session.posargs)
|
259
|
-
command.extend(filter_paths(CODE_FILES + ["noxfile.py"] + extra_code_files))
|
260
|
-
session.run(*command)
|
261
|
-
|
262
|
-
def execute_black_for(session: nox.Session, paths: list[str]) -> None:
|
263
|
-
if not paths:
|
264
|
-
return
|
265
|
-
command = ["black"]
|
266
|
-
if run_check:
|
267
|
-
command.append("--check")
|
268
|
-
if black_config is not None:
|
269
|
-
command.extend(["--config", str(black_config)])
|
270
|
-
command.extend(session.posargs)
|
271
|
-
command.extend(paths)
|
272
|
-
session.run(*command)
|
273
|
-
|
274
|
-
def execute_black(session: nox.Session) -> None:
|
275
|
-
if run_black and run_black_modules:
|
276
|
-
execute_black_for(
|
277
|
-
session, filter_paths(CODE_FILES + ["noxfile.py"] + extra_code_files)
|
278
|
-
)
|
279
|
-
return
|
280
|
-
if run_black:
|
281
|
-
paths = filter_paths(
|
282
|
-
CODE_FILES,
|
283
|
-
remove=MODULE_PATHS,
|
284
|
-
extensions=[".py"],
|
285
|
-
) + ["noxfile.py"]
|
286
|
-
execute_black_for(session, paths)
|
287
|
-
if run_black_modules:
|
288
|
-
paths = filter_paths(
|
289
|
-
CODE_FILES,
|
290
|
-
restrict=MODULE_PATHS,
|
291
|
-
extensions=[".py"],
|
292
|
-
)
|
293
|
-
execute_black_for(session, paths)
|
294
|
-
|
295
|
-
def formatters(session: nox.Session) -> None:
|
296
|
-
install(session, *compose_dependencies())
|
297
|
-
if run_isort:
|
298
|
-
execute_isort(session)
|
299
|
-
if run_black or run_black_modules:
|
300
|
-
execute_black(session)
|
301
|
-
|
302
|
-
nox.session(formatters, name="formatters", default=False) # type: ignore
|
303
|
-
|
304
|
-
|
305
|
-
def add_codeqa( # noqa: C901
|
306
|
-
*,
|
307
|
-
extra_code_files: list[str],
|
308
|
-
# flake8:
|
309
|
-
run_flake8: bool,
|
310
|
-
flake8_config: str | os.PathLike | None,
|
311
|
-
flake8_package: str,
|
312
|
-
# pylint:
|
313
|
-
run_pylint: bool,
|
314
|
-
pylint_rcfile: str | os.PathLike | None,
|
315
|
-
pylint_modules_rcfile: str | os.PathLike | None,
|
316
|
-
pylint_package: str,
|
317
|
-
pylint_ansible_core_package: str | None,
|
318
|
-
pylint_extra_deps: list[str],
|
319
|
-
) -> None:
|
320
|
-
"""
|
321
|
-
Add nox session for codeqa.
|
322
|
-
"""
|
323
|
-
|
324
|
-
def compose_dependencies() -> list[str]:
|
325
|
-
deps = []
|
326
|
-
if run_flake8:
|
327
|
-
deps.append(flake8_package)
|
328
|
-
if run_pylint:
|
329
|
-
deps.append(pylint_package)
|
330
|
-
if pylint_ansible_core_package is not None:
|
331
|
-
deps.append(pylint_ansible_core_package)
|
332
|
-
if os.path.isdir("tests/unit"):
|
333
|
-
deps.append("pytest")
|
334
|
-
if os.path.isfile("tests/unit/requirements.txt"):
|
335
|
-
deps.extend(["-r", "tests/unit/requirements.txt"])
|
336
|
-
for extra_dep in pylint_extra_deps:
|
337
|
-
deps.extend(shlex.split(extra_dep))
|
338
|
-
return deps
|
339
|
-
|
340
|
-
def execute_flake8(session: nox.Session) -> None:
|
341
|
-
command: list[str] = [
|
342
|
-
"flake8",
|
343
|
-
]
|
344
|
-
if flake8_config is not None:
|
345
|
-
command.extend(["--config", str(flake8_config)])
|
346
|
-
command.extend(session.posargs)
|
347
|
-
command.extend(filter_paths(CODE_FILES + ["noxfile.py"] + extra_code_files))
|
348
|
-
session.run(*command)
|
349
|
-
|
350
|
-
def execute_pylint_impl(
|
351
|
-
session: nox.Session,
|
352
|
-
prepared_collections: CollectionSetup,
|
353
|
-
config: os.PathLike | str | None,
|
354
|
-
paths: list[str],
|
355
|
-
) -> None:
|
356
|
-
command = ["pylint"]
|
357
|
-
if config is not None:
|
358
|
-
command.extend(
|
359
|
-
[
|
360
|
-
"--rcfile",
|
361
|
-
os.path.join(prepared_collections.current_collection.path, config),
|
362
|
-
]
|
363
|
-
)
|
364
|
-
command.extend(["--source-roots", "."])
|
365
|
-
command.extend(session.posargs)
|
366
|
-
command.extend(prepared_collections.prefix_current_paths(paths))
|
367
|
-
session.run(*command)
|
368
|
-
|
369
|
-
def execute_pylint(
|
370
|
-
session: nox.Session, prepared_collections: CollectionSetup
|
371
|
-
) -> None:
|
372
|
-
if pylint_modules_rcfile is not None and pylint_modules_rcfile != pylint_rcfile:
|
373
|
-
# Only run pylint twice when using different configurations
|
374
|
-
module_paths = filter_paths(
|
375
|
-
CODE_FILES, restrict=MODULE_PATHS, extensions=[".py"]
|
376
|
-
)
|
377
|
-
other_paths = filter_paths(
|
378
|
-
CODE_FILES, remove=MODULE_PATHS, extensions=[".py"]
|
379
|
-
)
|
380
|
-
else:
|
381
|
-
# Otherwise run it only once using the general configuration
|
382
|
-
module_paths = []
|
383
|
-
other_paths = filter_paths(CODE_FILES)
|
384
|
-
|
385
|
-
with session.chdir(prepared_collections.current_place):
|
386
|
-
if module_paths:
|
387
|
-
execute_pylint_impl(
|
388
|
-
session,
|
389
|
-
prepared_collections,
|
390
|
-
pylint_modules_rcfile or pylint_rcfile,
|
391
|
-
module_paths,
|
392
|
-
)
|
393
|
-
|
394
|
-
if other_paths:
|
395
|
-
execute_pylint_impl(
|
396
|
-
session, prepared_collections, pylint_rcfile, other_paths
|
397
|
-
)
|
398
|
-
|
399
|
-
def codeqa(session: nox.Session) -> None:
|
400
|
-
install(session, *compose_dependencies())
|
401
|
-
prepared_collections: CollectionSetup | None = None
|
402
|
-
if run_pylint:
|
403
|
-
prepared_collections = prepare_collections(
|
404
|
-
session,
|
405
|
-
install_in_site_packages=False,
|
406
|
-
extra_deps_files=["tests/unit/requirements.yml"],
|
407
|
-
)
|
408
|
-
if not prepared_collections:
|
409
|
-
session.warn("Skipping pylint...")
|
410
|
-
if run_flake8:
|
411
|
-
execute_flake8(session)
|
412
|
-
if run_pylint and prepared_collections:
|
413
|
-
execute_pylint(session, prepared_collections)
|
414
|
-
|
415
|
-
nox.session(codeqa, name="codeqa", default=False) # type: ignore
|
416
|
-
|
417
|
-
|
418
|
-
def add_typing(
|
419
|
-
*,
|
420
|
-
extra_code_files: list[str],
|
421
|
-
run_mypy: bool,
|
422
|
-
mypy_config: str | os.PathLike | None,
|
423
|
-
mypy_package: str,
|
424
|
-
mypy_ansible_core_package: str | None,
|
425
|
-
mypy_extra_deps: list[str],
|
426
|
-
) -> None:
|
427
|
-
"""
|
428
|
-
Add nox session for typing.
|
429
|
-
"""
|
430
|
-
|
431
|
-
def compose_dependencies() -> list[str]:
|
432
|
-
deps = []
|
433
|
-
if run_mypy:
|
434
|
-
deps.append(mypy_package)
|
435
|
-
if mypy_ansible_core_package is not None:
|
436
|
-
deps.append(mypy_ansible_core_package)
|
437
|
-
if os.path.isdir("tests/unit"):
|
438
|
-
deps.append("pytest")
|
439
|
-
if os.path.isfile("tests/unit/requirements.txt"):
|
440
|
-
deps.extend(["-r", "tests/unit/requirements.txt"])
|
441
|
-
for extra_dep in mypy_extra_deps:
|
442
|
-
deps.extend(shlex.split(extra_dep))
|
443
|
-
return deps
|
444
|
-
|
445
|
-
def execute_mypy(
|
446
|
-
session: nox.Session, prepared_collections: CollectionSetup
|
447
|
-
) -> None:
|
448
|
-
# Run mypy
|
449
|
-
with session.chdir(prepared_collections.current_place):
|
450
|
-
command = ["mypy"]
|
451
|
-
if mypy_config is not None:
|
452
|
-
command.extend(
|
453
|
-
[
|
454
|
-
"--config-file",
|
455
|
-
os.path.join(
|
456
|
-
prepared_collections.current_collection.path, mypy_config
|
457
|
-
),
|
458
|
-
]
|
459
|
-
)
|
460
|
-
command.append("--namespace-packages")
|
461
|
-
command.append("--explicit-package-bases")
|
462
|
-
command.extend(session.posargs)
|
463
|
-
command.extend(
|
464
|
-
prepared_collections.prefix_current_paths(CODE_FILES + extra_code_files)
|
465
|
-
)
|
466
|
-
session.run(
|
467
|
-
*command, env={"MYPYPATH": str(prepared_collections.current_place)}
|
468
|
-
)
|
469
|
-
|
470
|
-
def typing(session: nox.Session) -> None:
|
471
|
-
install(session, *compose_dependencies())
|
472
|
-
prepared_collections = prepare_collections(
|
473
|
-
session,
|
474
|
-
install_in_site_packages=False,
|
475
|
-
extra_deps_files=["tests/unit/requirements.yml"],
|
476
|
-
)
|
477
|
-
if not prepared_collections:
|
478
|
-
session.warn("Skipping mypy...")
|
479
|
-
if run_mypy and prepared_collections:
|
480
|
-
execute_mypy(session, prepared_collections)
|
481
|
-
|
482
|
-
nox.session(typing, name="typing", default=False) # type: ignore
|
483
|
-
|
484
|
-
|
485
|
-
def add_lint_sessions(
|
486
|
-
*,
|
487
|
-
make_lint_default: bool = True,
|
488
|
-
extra_code_files: list[str] | None = None,
|
489
|
-
# isort:
|
490
|
-
run_isort: bool = True,
|
491
|
-
isort_config: str | os.PathLike | None = None,
|
492
|
-
isort_package: str = "isort",
|
493
|
-
# black:
|
494
|
-
run_black: bool = True,
|
495
|
-
run_black_modules: bool | None = None,
|
496
|
-
black_config: str | os.PathLike | None = None,
|
497
|
-
black_package: str = "black",
|
498
|
-
# flake8:
|
499
|
-
run_flake8: bool = True,
|
500
|
-
flake8_config: str | os.PathLike | None = None,
|
501
|
-
flake8_package: str = "flake8",
|
502
|
-
# pylint:
|
503
|
-
run_pylint: bool = True,
|
504
|
-
pylint_rcfile: str | os.PathLike | None = None,
|
505
|
-
pylint_modules_rcfile: str | os.PathLike | None = None,
|
506
|
-
pylint_package: str = "pylint",
|
507
|
-
pylint_ansible_core_package: str | None = "ansible-core",
|
508
|
-
pylint_extra_deps: list[str] | None = None,
|
509
|
-
# mypy:
|
510
|
-
run_mypy: bool = True,
|
511
|
-
mypy_config: str | os.PathLike | None = None,
|
512
|
-
mypy_package: str = "mypy",
|
513
|
-
mypy_ansible_core_package: str | None = "ansible-core",
|
514
|
-
mypy_extra_deps: list[str] | None = None,
|
515
|
-
) -> None:
|
516
|
-
"""
|
517
|
-
Add nox sessions for linting.
|
518
|
-
"""
|
519
|
-
has_formatters = run_isort or run_black or run_black_modules or False
|
520
|
-
has_codeqa = run_flake8 or run_pylint
|
521
|
-
has_typing = run_mypy
|
522
|
-
|
523
|
-
add_lint(
|
524
|
-
has_formatters=has_formatters,
|
525
|
-
has_codeqa=has_codeqa,
|
526
|
-
has_typing=has_typing,
|
527
|
-
make_lint_default=make_lint_default,
|
528
|
-
)
|
529
|
-
|
530
|
-
if has_formatters:
|
531
|
-
add_formatters(
|
532
|
-
extra_code_files=extra_code_files or [],
|
533
|
-
run_isort=run_isort,
|
534
|
-
isort_config=isort_config,
|
535
|
-
isort_package=isort_package,
|
536
|
-
run_black=run_black,
|
537
|
-
run_black_modules=run_black_modules,
|
538
|
-
black_config=black_config,
|
539
|
-
black_package=black_package,
|
540
|
-
)
|
541
|
-
|
542
|
-
if has_codeqa:
|
543
|
-
add_codeqa(
|
544
|
-
extra_code_files=extra_code_files or [],
|
545
|
-
run_flake8=run_flake8,
|
546
|
-
flake8_config=flake8_config,
|
547
|
-
flake8_package=flake8_package,
|
548
|
-
run_pylint=run_pylint,
|
549
|
-
pylint_rcfile=pylint_rcfile,
|
550
|
-
pylint_modules_rcfile=pylint_modules_rcfile,
|
551
|
-
pylint_package=pylint_package,
|
552
|
-
pylint_ansible_core_package=pylint_ansible_core_package,
|
553
|
-
pylint_extra_deps=pylint_extra_deps or [],
|
554
|
-
)
|
555
|
-
|
556
|
-
if has_typing:
|
557
|
-
add_typing(
|
558
|
-
extra_code_files=extra_code_files or [],
|
559
|
-
run_mypy=run_mypy,
|
560
|
-
mypy_config=mypy_config,
|
561
|
-
mypy_package=mypy_package,
|
562
|
-
mypy_ansible_core_package=mypy_ansible_core_package,
|
563
|
-
mypy_extra_deps=mypy_extra_deps or [],
|
564
|
-
)
|
565
|
-
|
566
|
-
|
567
|
-
def add_docs_check(
|
568
|
-
*,
|
569
|
-
make_docs_check_default: bool = True,
|
570
|
-
antsibull_docs_package: str = "antsibull-docs",
|
571
|
-
ansible_core_package: str = "ansible-core",
|
572
|
-
validate_collection_refs: t.Literal["self", "dependent", "all"] | None = None,
|
573
|
-
extra_collections: list[str] | None = None,
|
574
|
-
):
|
575
|
-
"""
|
576
|
-
Add docs-check session for linting.
|
577
|
-
"""
|
578
|
-
|
579
|
-
def compose_dependencies() -> list[str]:
|
580
|
-
deps = [antsibull_docs_package, ansible_core_package]
|
581
|
-
return deps
|
582
|
-
|
583
|
-
def execute_antsibull_docs(
|
584
|
-
session: nox.Session, prepared_collections: CollectionSetup
|
585
|
-
) -> None:
|
586
|
-
with session.chdir(prepared_collections.current_path):
|
587
|
-
collections_path = f"{prepared_collections.current_place}"
|
588
|
-
command = [
|
589
|
-
"antsibull-docs",
|
590
|
-
"lint-collection-docs",
|
591
|
-
"--plugin-docs",
|
592
|
-
"--skip-rstcheck",
|
593
|
-
".",
|
594
|
-
]
|
595
|
-
if validate_collection_refs:
|
596
|
-
command.extend(["--validate-collection-refs", validate_collection_refs])
|
597
|
-
session.run(*command, env={"ANSIBLE_COLLECTIONS_PATH": collections_path})
|
598
|
-
|
599
|
-
def docs_check(session: nox.Session) -> None:
|
600
|
-
install(session, *compose_dependencies())
|
601
|
-
prepared_collections = prepare_collections(
|
602
|
-
session,
|
603
|
-
install_in_site_packages=False,
|
604
|
-
extra_collections=extra_collections,
|
605
|
-
install_out_of_tree=True,
|
606
|
-
)
|
607
|
-
if not prepared_collections:
|
608
|
-
session.warn("Skipping antsibull-docs...")
|
609
|
-
if prepared_collections:
|
610
|
-
execute_antsibull_docs(session, prepared_collections)
|
611
|
-
|
612
|
-
nox.session( # type: ignore
|
613
|
-
docs_check, name="docs-check", default=make_docs_check_default
|
614
|
-
)
|
615
|
-
|
616
|
-
|
617
|
-
def add_license_check(
|
618
|
-
*,
|
619
|
-
make_license_check_default: bool = True,
|
620
|
-
run_reuse: bool = True,
|
621
|
-
reuse_package: str = "reuse",
|
622
|
-
run_license_check: bool = True,
|
623
|
-
license_check_extra_ignore_paths: list[str] | None = None,
|
624
|
-
):
|
625
|
-
"""
|
626
|
-
Add license-check session for license checks.
|
627
|
-
"""
|
628
|
-
|
629
|
-
def compose_dependencies() -> list[str]:
|
630
|
-
deps = []
|
631
|
-
if run_reuse:
|
632
|
-
deps.append(reuse_package)
|
633
|
-
return deps
|
634
|
-
|
635
|
-
def license_check(session: nox.Session) -> None:
|
636
|
-
install(session, *compose_dependencies())
|
637
|
-
if run_reuse:
|
638
|
-
session.run("reuse", "lint")
|
639
|
-
if run_license_check:
|
640
|
-
_run_bare_script(
|
641
|
-
session,
|
642
|
-
"license-check",
|
643
|
-
extra_data={
|
644
|
-
"extra_ignore_paths": license_check_extra_ignore_paths or [],
|
645
|
-
},
|
646
|
-
)
|
647
|
-
|
648
|
-
nox.session( # type: ignore
|
649
|
-
license_check, name="license-check", default=make_license_check_default
|
650
|
-
)
|
651
|
-
|
652
|
-
|
653
|
-
@dataclass
|
654
|
-
class ActionGroup:
|
655
|
-
"""
|
656
|
-
Defines an action group.
|
657
|
-
"""
|
658
|
-
|
659
|
-
# Name of the action group.
|
660
|
-
name: str
|
661
|
-
# Regex pattern to match modules that could belong to this action group.
|
662
|
-
pattern: str
|
663
|
-
# Doc fragment that members of the action group must have, but no other module
|
664
|
-
# must have
|
665
|
-
doc_fragment: str
|
666
|
-
# Exclusion list of modules that match the regex, but should not be part of the
|
667
|
-
# action group. All other modules matching the regex are assumed to be part of
|
668
|
-
# the action group.
|
669
|
-
exclusions: list[str] | None = None
|
670
|
-
|
671
|
-
|
672
|
-
def add_extra_checks(
|
673
|
-
*,
|
674
|
-
make_extra_checks_default: bool = True,
|
675
|
-
# no-unwanted-files:
|
676
|
-
run_no_unwanted_files: bool = True,
|
677
|
-
no_unwanted_files_module_extensions: (
|
678
|
-
list[str] | None
|
679
|
-
) = None, # default: .cs, .ps1, .psm1, .py
|
680
|
-
no_unwanted_files_other_extensions: list[str] | None = None, # default: .py, .pyi
|
681
|
-
no_unwanted_files_yaml_extensions: list[str] | None = None, # default: .yml, .yaml
|
682
|
-
no_unwanted_files_skip_paths: list[str] | None = None, # default: []
|
683
|
-
no_unwanted_files_skip_directories: list[str] | None = None, # default: []
|
684
|
-
no_unwanted_files_yaml_directories: (
|
685
|
-
list[str] | None
|
686
|
-
) = None, # default: plugins/test/, plugins/filter/
|
687
|
-
no_unwanted_files_allow_symlinks: bool = False,
|
688
|
-
# action-groups:
|
689
|
-
run_action_groups: bool = False,
|
690
|
-
action_groups_config: list[ActionGroup] | None = None,
|
691
|
-
):
|
692
|
-
"""
|
693
|
-
Add extra-checks session for extra checks.
|
694
|
-
"""
|
695
|
-
|
696
|
-
def execute_no_unwanted_files(session: nox.Session) -> None:
|
697
|
-
_run_bare_script(
|
698
|
-
session,
|
699
|
-
"no-unwanted-files",
|
700
|
-
extra_data={
|
701
|
-
"module_extensions": no_unwanted_files_module_extensions
|
702
|
-
or [".cs", ".ps1", ".psm1", ".py"],
|
703
|
-
"other_extensions": no_unwanted_files_other_extensions
|
704
|
-
or [".py", ".pyi"],
|
705
|
-
"yaml_extensions": no_unwanted_files_yaml_extensions
|
706
|
-
or [".yml", ".yaml"],
|
707
|
-
"skip_paths": no_unwanted_files_skip_paths or [],
|
708
|
-
"skip_directories": no_unwanted_files_skip_directories or [],
|
709
|
-
"yaml_directories": no_unwanted_files_yaml_directories
|
710
|
-
or ["plugins/test/", "plugins/filter/"],
|
711
|
-
"allow_symlinks": no_unwanted_files_allow_symlinks,
|
712
|
-
},
|
713
|
-
)
|
714
|
-
|
715
|
-
def execute_action_groups(session: nox.Session) -> None:
|
716
|
-
if action_groups_config is None:
|
717
|
-
session.warn("Skipping action-groups since config is not provided...")
|
718
|
-
return
|
719
|
-
_run_bare_script(
|
720
|
-
session,
|
721
|
-
"action-groups",
|
722
|
-
extra_data={
|
723
|
-
"config": [asdict(cfg) for cfg in action_groups_config],
|
724
|
-
},
|
725
|
-
)
|
726
|
-
|
727
|
-
def extra_checks(session: nox.Session) -> None:
|
728
|
-
if run_no_unwanted_files:
|
729
|
-
execute_no_unwanted_files(session)
|
730
|
-
if run_action_groups:
|
731
|
-
execute_action_groups(session)
|
732
|
-
|
733
|
-
nox.session( # type: ignore
|
734
|
-
extra_checks,
|
735
|
-
name="extra-checks",
|
736
|
-
python=False,
|
737
|
-
default=make_extra_checks_default,
|
738
|
-
)
|
739
|
-
|
740
|
-
|
741
|
-
def add_build_import_check(
|
742
|
-
*,
|
743
|
-
make_build_import_check_default: bool = True,
|
744
|
-
ansible_core_package: str = "ansible-core",
|
745
|
-
run_galaxy_importer: bool = True,
|
746
|
-
galaxy_importer_package: str = "galaxy-importer",
|
747
|
-
galaxy_importer_config_path: (
|
748
|
-
str | None
|
749
|
-
) = None, # https://github.com/ansible/galaxy-importer#configuration
|
750
|
-
):
|
751
|
-
"""
|
752
|
-
Add license-check session for license checks.
|
753
|
-
"""
|
754
|
-
|
755
|
-
def compose_dependencies() -> list[str]:
|
756
|
-
deps = [ansible_core_package]
|
757
|
-
if run_galaxy_importer:
|
758
|
-
deps.append(galaxy_importer_package)
|
759
|
-
return deps
|
760
|
-
|
761
|
-
def build_import_check(session: nox.Session) -> None:
|
762
|
-
install(session, *compose_dependencies())
|
763
|
-
|
764
|
-
tmp = Path(session.create_tmp())
|
765
|
-
collection_dir = tmp / "collection"
|
766
|
-
remove_path(collection_dir)
|
767
|
-
copy_collection(Path.cwd(), collection_dir)
|
768
|
-
|
769
|
-
collection = load_collection_data_from_disk(
|
770
|
-
collection_dir, accept_manifest=False
|
771
|
-
)
|
772
|
-
version = collection.version
|
773
|
-
if not version:
|
774
|
-
version = "0.0.1"
|
775
|
-
force_collection_version(collection_dir, version=version)
|
776
|
-
|
777
|
-
with session.chdir(collection_dir):
|
778
|
-
build_ran = session.run("ansible-galaxy", "collection", "build") is not None
|
779
|
-
|
780
|
-
tarball = (
|
781
|
-
collection_dir
|
782
|
-
/ f"{collection.namespace}-{collection.name}-{version}.tar.gz"
|
783
|
-
)
|
784
|
-
if build_ran and not tarball.is_file():
|
785
|
-
files = "\n".join(
|
786
|
-
f"* {path.name}"
|
787
|
-
for path in collection_dir.iterdir()
|
788
|
-
if not path.is_dir()
|
789
|
-
)
|
790
|
-
session.error(f"Cannot find file {tarball}! List of all files:\n{files}")
|
791
|
-
|
792
|
-
if run_galaxy_importer and tarball.is_file():
|
793
|
-
env = {}
|
794
|
-
if galaxy_importer_config_path:
|
795
|
-
env["GALAXY_IMPORTER_CONFIG"] = str(
|
796
|
-
Path.cwd() / galaxy_importer_config_path
|
797
|
-
)
|
798
|
-
with session.chdir(collection_dir):
|
799
|
-
import_log = (
|
800
|
-
session.run(
|
801
|
-
"python",
|
802
|
-
"-m",
|
803
|
-
"galaxy_importer.main",
|
804
|
-
tarball.name,
|
805
|
-
env=env,
|
806
|
-
silent=True,
|
807
|
-
)
|
808
|
-
or ""
|
809
|
-
)
|
810
|
-
if import_log:
|
811
|
-
print(import_log)
|
812
|
-
error_prefix = "ERROR:"
|
813
|
-
errors = []
|
814
|
-
for line in import_log.splitlines():
|
815
|
-
if line.startswith(error_prefix):
|
816
|
-
errors.append(line[len(error_prefix) :].strip())
|
817
|
-
if errors:
|
818
|
-
messages = "\n".join(f"* {error}" for error in errors)
|
819
|
-
session.warn(
|
820
|
-
"Galaxy importer emitted the following non-fatal"
|
821
|
-
f" error{'' if len(errors) == 1 else 's'}:\n{messages}"
|
822
|
-
)
|
823
|
-
|
824
|
-
nox.session( # type: ignore
|
825
|
-
build_import_check,
|
826
|
-
name="build-import-check",
|
827
|
-
default=make_build_import_check_default,
|
828
|
-
)
|
829
|
-
|
830
|
-
|
831
|
-
__all__ = [
|
832
|
-
"ActionGroup",
|
833
|
-
"add_build_import_check",
|
834
|
-
"add_docs_check",
|
835
|
-
"add_extra_checks",
|
836
|
-
"add_license_check",
|
837
|
-
"add_lint_sessions",
|
838
|
-
"install",
|
839
|
-
"prepare_collections",
|
840
|
-
]
|