antsibull-nox 0.2.0__py3-none-any.whl → 0.4.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.
Files changed (34) hide show
  1. antsibull_nox/__init__.py +7 -51
  2. antsibull_nox/_pydantic.py +98 -0
  3. antsibull_nox/ansible.py +15 -0
  4. antsibull_nox/cli.py +132 -0
  5. antsibull_nox/collection/__init__.py +2 -2
  6. antsibull_nox/collection/data.py +12 -0
  7. antsibull_nox/collection/install.py +194 -79
  8. antsibull_nox/collection/search.py +136 -34
  9. antsibull_nox/config.py +51 -2
  10. antsibull_nox/data/action-groups.py +2 -2
  11. antsibull_nox/data/antsibull-nox-lint-config.py +29 -0
  12. antsibull_nox/data/file-yamllint.py +138 -0
  13. antsibull_nox/data/license-check.py +5 -1
  14. antsibull_nox/data/plugin-yamllint.py +54 -24
  15. antsibull_nox/init.py +83 -0
  16. antsibull_nox/interpret_config.py +29 -8
  17. antsibull_nox/lint_config.py +113 -0
  18. antsibull_nox/sessions/__init__.py +70 -0
  19. antsibull_nox/sessions/ansible_lint.py +60 -0
  20. antsibull_nox/sessions/ansible_test.py +559 -0
  21. antsibull_nox/sessions/build_import_check.py +147 -0
  22. antsibull_nox/sessions/collections.py +145 -0
  23. antsibull_nox/sessions/docs_check.py +78 -0
  24. antsibull_nox/sessions/extra_checks.py +127 -0
  25. antsibull_nox/sessions/license_check.py +73 -0
  26. antsibull_nox/sessions/lint.py +694 -0
  27. antsibull_nox/sessions/utils.py +206 -0
  28. {antsibull_nox-0.2.0.dist-info → antsibull_nox-0.4.0.dist-info}/METADATA +2 -2
  29. antsibull_nox-0.4.0.dist-info/RECORD +41 -0
  30. antsibull_nox-0.4.0.dist-info/entry_points.txt +2 -0
  31. antsibull_nox/sessions.py +0 -1712
  32. antsibull_nox-0.2.0.dist-info/RECORD +0 -25
  33. {antsibull_nox-0.2.0.dist-info → antsibull_nox-0.4.0.dist-info}/WHEEL +0 -0
  34. {antsibull_nox-0.2.0.dist-info → antsibull_nox-0.4.0.dist-info}/licenses/LICENSES/GPL-3.0-or-later.txt +0 -0
@@ -0,0 +1,559 @@
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-test sessions.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import os
14
+ import typing as t
15
+ from collections.abc import Callable
16
+ from pathlib import Path
17
+
18
+ import nox
19
+
20
+ from ..ansible import (
21
+ AnsibleCoreVersion,
22
+ get_ansible_core_info,
23
+ get_ansible_core_package_name,
24
+ get_supported_core_versions,
25
+ parse_ansible_core_version,
26
+ )
27
+ from ..paths import copy_directory_tree_into
28
+ from ..python import get_installed_python_versions
29
+ from ..utils import Version
30
+ from .collections import prepare_collections
31
+ from .utils import (
32
+ install,
33
+ register,
34
+ )
35
+
36
+
37
+ def add_ansible_test_session(
38
+ *,
39
+ name: str,
40
+ description: str | None,
41
+ extra_deps_files: list[str | os.PathLike] | None = None,
42
+ ansible_test_params: list[str],
43
+ add_posargs: bool = True,
44
+ default: bool,
45
+ ansible_core_version: str | AnsibleCoreVersion,
46
+ ansible_core_source: t.Literal["git", "pypi"] = "git",
47
+ ansible_core_repo_name: str | None = None,
48
+ ansible_core_branch_name: str | None = None,
49
+ handle_coverage: t.Literal["never", "always", "auto"] = "auto",
50
+ register_name: str | None = None,
51
+ register_extra_data: dict[str, t.Any] | None = None,
52
+ callback_before: Callable[[], None] | None = None,
53
+ callback_after: Callable[[], None] | None = None,
54
+ ) -> None:
55
+ """
56
+ Add generic ansible-test session.
57
+
58
+ Returns a list of Python versions set for this session.
59
+ """
60
+ parsed_ansible_core_version = parse_ansible_core_version(ansible_core_version)
61
+
62
+ def compose_dependencies() -> list[str]:
63
+ deps = [
64
+ get_ansible_core_package_name(
65
+ parsed_ansible_core_version,
66
+ source=ansible_core_source,
67
+ ansible_repo=ansible_core_repo_name,
68
+ branch_name=ansible_core_branch_name,
69
+ )
70
+ ]
71
+ return deps
72
+
73
+ def run_ansible_test(session: nox.Session) -> None:
74
+ install(session, *compose_dependencies())
75
+ prepared_collections = prepare_collections(
76
+ session,
77
+ ansible_core_version=parsed_ansible_core_version,
78
+ install_in_site_packages=False,
79
+ extra_deps_files=extra_deps_files,
80
+ install_out_of_tree=True,
81
+ )
82
+ if not prepared_collections:
83
+ session.warn("Skipping ansible-test...")
84
+ return
85
+ cwd = Path.cwd()
86
+ with session.chdir(prepared_collections.current_path):
87
+ if callback_before:
88
+ callback_before()
89
+
90
+ command = ["ansible-test"] + ansible_test_params
91
+ if add_posargs and session.posargs:
92
+ command.extend(session.posargs)
93
+ session.run(*command)
94
+
95
+ coverage = (handle_coverage == "auto" and "--coverage" in command) or (
96
+ handle_coverage == "always"
97
+ )
98
+ if coverage:
99
+ session.run(
100
+ "ansible-test",
101
+ "coverage",
102
+ "xml",
103
+ "--color",
104
+ "-v",
105
+ "--requirements",
106
+ "--group-by",
107
+ "command",
108
+ "--group-by",
109
+ "version",
110
+ )
111
+
112
+ if callback_after:
113
+ callback_after()
114
+
115
+ copy_directory_tree_into(
116
+ prepared_collections.current_path / "tests" / "output",
117
+ cwd / "tests" / "output",
118
+ )
119
+
120
+ # Determine Python version(s)
121
+ core_info = get_ansible_core_info(parsed_ansible_core_version)
122
+ all_versions = get_installed_python_versions()
123
+
124
+ installed_versions = [
125
+ version
126
+ for version in core_info.controller_python_versions
127
+ if version in all_versions
128
+ ]
129
+ python = max(installed_versions or core_info.controller_python_versions)
130
+ python_versions = [python]
131
+
132
+ run_ansible_test.__doc__ = description
133
+ nox.session(
134
+ name=name,
135
+ default=default,
136
+ python=[str(python_version) for python_version in python_versions],
137
+ )(run_ansible_test)
138
+
139
+ if register_name:
140
+ data = {
141
+ "name": name,
142
+ "ansible-core": (
143
+ str(ansible_core_branch_name)
144
+ if ansible_core_branch_name is not None
145
+ else str(parsed_ansible_core_version)
146
+ ),
147
+ "python": " ".join(str(python) for python in python_versions),
148
+ }
149
+ if register_extra_data:
150
+ data.update(register_extra_data)
151
+ register(register_name, data)
152
+
153
+
154
+ def add_ansible_test_sanity_test_session(
155
+ *,
156
+ name: str,
157
+ description: str | None,
158
+ default: bool,
159
+ ansible_core_version: str | AnsibleCoreVersion,
160
+ ansible_core_source: t.Literal["git", "pypi"] = "git",
161
+ ansible_core_repo_name: str | None = None,
162
+ ansible_core_branch_name: str | None = None,
163
+ skip_tests: list[str] | None = None,
164
+ allow_disabled: bool = False,
165
+ enable_optional_errors: bool = False,
166
+ register_extra_data: dict[str, t.Any] | None = None,
167
+ ) -> None:
168
+ """
169
+ Add generic ansible-test sanity test session.
170
+ """
171
+ command = ["sanity", "--docker", "-v", "--color"]
172
+ if skip_tests:
173
+ for test in skip_tests:
174
+ command.extend(["--skip", test])
175
+ if allow_disabled:
176
+ command.append("--allow-disabled")
177
+ if enable_optional_errors:
178
+ command.append("--enable-optional-errors")
179
+ add_ansible_test_session(
180
+ name=name,
181
+ description=description,
182
+ ansible_test_params=command,
183
+ default=default,
184
+ ansible_core_version=ansible_core_version,
185
+ ansible_core_source=ansible_core_source,
186
+ ansible_core_repo_name=ansible_core_repo_name,
187
+ ansible_core_branch_name=ansible_core_branch_name,
188
+ register_name="sanity",
189
+ register_extra_data=register_extra_data,
190
+ )
191
+
192
+
193
+ def _parse_min_max_except(
194
+ min_version: Version | str | None,
195
+ max_version: Version | str | None,
196
+ except_versions: list[AnsibleCoreVersion | str] | None,
197
+ ) -> tuple[Version | None, Version | None, tuple[AnsibleCoreVersion, ...] | None]:
198
+ if isinstance(min_version, str):
199
+ min_version = Version.parse(min_version)
200
+ if isinstance(max_version, str):
201
+ max_version = Version.parse(max_version)
202
+ if except_versions is None:
203
+ return min_version, max_version, None
204
+ evs = tuple(parse_ansible_core_version(version) for version in except_versions)
205
+ return min_version, max_version, evs
206
+
207
+
208
+ def add_all_ansible_test_sanity_test_sessions(
209
+ *,
210
+ default: bool = False,
211
+ include_devel: bool = False,
212
+ include_milestone: bool = False,
213
+ add_devel_like_branches: list[tuple[str | None, str]] | None = None,
214
+ min_version: Version | str | None = None,
215
+ max_version: Version | str | None = None,
216
+ except_versions: list[AnsibleCoreVersion | str] | None = None,
217
+ skip_tests: list[str] | None = None,
218
+ allow_disabled: bool = False,
219
+ enable_optional_errors: bool = False,
220
+ ) -> None:
221
+ """
222
+ Add ansible-test sanity test meta session that runs ansible-test sanity
223
+ for all supported ansible-core versions.
224
+ """
225
+ parsed_min_version, parsed_max_version, parsed_except_versions = (
226
+ _parse_min_max_except(min_version, max_version, except_versions)
227
+ )
228
+
229
+ sanity_sessions = []
230
+ for ansible_core_version in get_supported_core_versions(
231
+ include_devel=include_devel,
232
+ include_milestone=include_milestone,
233
+ min_version=parsed_min_version,
234
+ max_version=parsed_max_version,
235
+ except_versions=parsed_except_versions,
236
+ ):
237
+ name = f"ansible-test-sanity-{ansible_core_version}"
238
+ add_ansible_test_sanity_test_session(
239
+ name=name,
240
+ description=f"Run sanity tests from ansible-core {ansible_core_version}'s ansible-test",
241
+ ansible_core_version=ansible_core_version,
242
+ skip_tests=skip_tests,
243
+ allow_disabled=allow_disabled,
244
+ enable_optional_errors=enable_optional_errors,
245
+ register_extra_data={"display-name": f"Ⓐ{ansible_core_version}"},
246
+ default=False,
247
+ )
248
+ sanity_sessions.append(name)
249
+ if add_devel_like_branches:
250
+ for repo_name, branch_name in add_devel_like_branches:
251
+ repo_prefix = (
252
+ f"{repo_name.replace('/', '-')}-" if repo_name is not None else ""
253
+ )
254
+ repo_postfix = f", {repo_name} repository" if repo_name is not None else ""
255
+ name = f"ansible-test-sanity-{repo_prefix}{branch_name.replace('/', '-')}"
256
+ add_ansible_test_sanity_test_session(
257
+ name=name,
258
+ description=(
259
+ "Run sanity tests from ansible-test in ansible-core's"
260
+ f" {branch_name} branch{repo_postfix}"
261
+ ),
262
+ ansible_core_version="devel",
263
+ ansible_core_repo_name=repo_name,
264
+ ansible_core_branch_name=branch_name,
265
+ skip_tests=skip_tests,
266
+ allow_disabled=allow_disabled,
267
+ enable_optional_errors=enable_optional_errors,
268
+ register_extra_data={"display-name": f"Ⓐ{branch_name}"},
269
+ default=False,
270
+ )
271
+ sanity_sessions.append(name)
272
+
273
+ def run_all_sanity_tests(
274
+ session: nox.Session, # pylint: disable=unused-argument
275
+ ) -> None:
276
+ pass
277
+
278
+ run_all_sanity_tests.__doc__ = (
279
+ "Meta session for running all ansible-test-sanity-* sessions."
280
+ )
281
+ nox.session(
282
+ name="ansible-test-sanity",
283
+ default=default,
284
+ requires=sanity_sessions,
285
+ )(run_all_sanity_tests)
286
+
287
+
288
+ def add_ansible_test_unit_test_session(
289
+ *,
290
+ name: str,
291
+ description: str | None,
292
+ default: bool,
293
+ ansible_core_version: str | AnsibleCoreVersion,
294
+ ansible_core_source: t.Literal["git", "pypi"] = "git",
295
+ ansible_core_repo_name: str | None = None,
296
+ ansible_core_branch_name: str | None = None,
297
+ register_extra_data: dict[str, t.Any] | None = None,
298
+ ) -> None:
299
+ """
300
+ Add generic ansible-test unit test session.
301
+ """
302
+ add_ansible_test_session(
303
+ name=name,
304
+ description=description,
305
+ ansible_test_params=["units", "--docker", "-v", "--color"],
306
+ extra_deps_files=["tests/unit/requirements.yml"],
307
+ default=default,
308
+ ansible_core_version=ansible_core_version,
309
+ ansible_core_source=ansible_core_source,
310
+ ansible_core_repo_name=ansible_core_repo_name,
311
+ ansible_core_branch_name=ansible_core_branch_name,
312
+ register_name="units",
313
+ register_extra_data=register_extra_data,
314
+ )
315
+
316
+
317
+ def add_all_ansible_test_unit_test_sessions(
318
+ *,
319
+ default: bool = False,
320
+ include_devel: bool = False,
321
+ include_milestone: bool = False,
322
+ add_devel_like_branches: list[tuple[str | None, str]] | None = None,
323
+ min_version: Version | str | None = None,
324
+ max_version: Version | str | None = None,
325
+ except_versions: list[AnsibleCoreVersion | str] | None = None,
326
+ ) -> None:
327
+ """
328
+ Add ansible-test unit test meta session that runs ansible-test units
329
+ for all supported ansible-core versions.
330
+ """
331
+ parsed_min_version, parsed_max_version, parsed_except_versions = (
332
+ _parse_min_max_except(min_version, max_version, except_versions)
333
+ )
334
+
335
+ units_sessions = []
336
+ for ansible_core_version in get_supported_core_versions(
337
+ include_devel=include_devel,
338
+ include_milestone=include_milestone,
339
+ min_version=parsed_min_version,
340
+ max_version=parsed_max_version,
341
+ except_versions=parsed_except_versions,
342
+ ):
343
+ name = f"ansible-test-units-{ansible_core_version}"
344
+ add_ansible_test_unit_test_session(
345
+ name=name,
346
+ description=f"Run unit tests with ansible-core {ansible_core_version}'s ansible-test",
347
+ ansible_core_version=ansible_core_version,
348
+ register_extra_data={"display-name": f"Ⓐ{ansible_core_version}"},
349
+ default=False,
350
+ )
351
+ units_sessions.append(name)
352
+ if add_devel_like_branches:
353
+ for repo_name, branch_name in add_devel_like_branches:
354
+ repo_prefix = (
355
+ f"{repo_name.replace('/', '-')}-" if repo_name is not None else ""
356
+ )
357
+ repo_postfix = f", {repo_name} repository" if repo_name is not None else ""
358
+ name = f"ansible-test-units-{repo_prefix}{branch_name.replace('/', '-')}"
359
+ add_ansible_test_unit_test_session(
360
+ name=name,
361
+ description=(
362
+ "Run unit tests from ansible-test in ansible-core's"
363
+ f" {branch_name} branch{repo_postfix}"
364
+ ),
365
+ ansible_core_version="devel",
366
+ ansible_core_repo_name=repo_name,
367
+ ansible_core_branch_name=branch_name,
368
+ register_extra_data={"display-name": f"Ⓐ{branch_name}"},
369
+ default=False,
370
+ )
371
+ units_sessions.append(name)
372
+
373
+ def run_all_unit_tests(
374
+ session: nox.Session, # pylint: disable=unused-argument
375
+ ) -> None:
376
+ pass
377
+
378
+ run_all_unit_tests.__doc__ = (
379
+ "Meta session for running all ansible-test-units-* sessions."
380
+ )
381
+ nox.session(
382
+ name="ansible-test-units",
383
+ default=default,
384
+ requires=units_sessions,
385
+ )(run_all_unit_tests)
386
+
387
+
388
+ def add_ansible_test_integration_sessions_default_container(
389
+ *,
390
+ include_devel: bool = False,
391
+ include_milestone: bool = False,
392
+ add_devel_like_branches: list[tuple[str | None, str]] | None = None,
393
+ min_version: Version | str | None = None,
394
+ max_version: Version | str | None = None,
395
+ except_versions: list[AnsibleCoreVersion | str] | None = None,
396
+ core_python_versions: (
397
+ dict[str | AnsibleCoreVersion, list[str | Version]] | None
398
+ ) = None,
399
+ controller_python_versions_only: bool = False,
400
+ default: bool = False,
401
+ ) -> None:
402
+ """
403
+ Add ansible-test integration tests using the default Docker container.
404
+
405
+ ``core_python_versions`` can be used to restrict the Python versions
406
+ to be used for a specific ansible-core version.
407
+
408
+ ``controller_python_versions_only`` can be used to only run against
409
+ controller Python versions.
410
+ """
411
+
412
+ def add_integration_tests(
413
+ ansible_core_version: AnsibleCoreVersion,
414
+ repo_name: str | None = None,
415
+ branch_name: str | None = None,
416
+ ) -> list[str]:
417
+ # Determine Python versions to run tests for
418
+ py_versions = (
419
+ (core_python_versions.get(branch_name) if branch_name is not None else None)
420
+ or core_python_versions.get(ansible_core_version)
421
+ or core_python_versions.get(str(ansible_core_version))
422
+ if core_python_versions
423
+ else None
424
+ )
425
+ if py_versions is None:
426
+ core_info = get_ansible_core_info(ansible_core_version)
427
+ py_versions = list(
428
+ core_info.controller_python_versions
429
+ if controller_python_versions_only
430
+ else core_info.remote_python_versions
431
+ )
432
+
433
+ # Add sessions
434
+ integration_sessions_core: list[str] = []
435
+ if branch_name is None:
436
+ base_name = f"ansible-test-integration-{ansible_core_version}-"
437
+ else:
438
+ repo_prefix = (
439
+ f"{repo_name.replace('/', '-')}-" if repo_name is not None else ""
440
+ )
441
+ base_name = f"ansible-test-integration-{repo_prefix}{branch_name.replace('/', '-')}-"
442
+ for py_version in py_versions:
443
+ name = f"{base_name}{py_version}"
444
+ if branch_name is None:
445
+ description = (
446
+ f"Run integration tests from ansible-core {ansible_core_version}'s"
447
+ f" ansible-test with Python {py_version}"
448
+ )
449
+ else:
450
+ repo_postfix = (
451
+ f", {repo_name} repository" if repo_name is not None else ""
452
+ )
453
+ description = (
454
+ f"Run integration tests from ansible-test in ansible-core's {branch_name}"
455
+ f" branch{repo_postfix} with Python {py_version}"
456
+ )
457
+ add_ansible_test_session(
458
+ name=name,
459
+ description=description,
460
+ ansible_test_params=[
461
+ "integration",
462
+ "--docker",
463
+ "default",
464
+ "-v",
465
+ "--color",
466
+ "--python",
467
+ str(py_version),
468
+ ],
469
+ extra_deps_files=["tests/integration/requirements.yml"],
470
+ ansible_core_version=ansible_core_version,
471
+ ansible_core_repo_name=repo_name,
472
+ ansible_core_branch_name=branch_name,
473
+ default=False,
474
+ register_name="integration",
475
+ register_extra_data={
476
+ "display-name": f"Ⓐ{ansible_core_version}+py{py_version}+default"
477
+ },
478
+ )
479
+ integration_sessions_core.append(name)
480
+ return integration_sessions_core
481
+
482
+ parsed_min_version, parsed_max_version, parsed_except_versions = (
483
+ _parse_min_max_except(min_version, max_version, except_versions)
484
+ )
485
+ integration_sessions: list[str] = []
486
+ for ansible_core_version in get_supported_core_versions(
487
+ include_devel=include_devel,
488
+ include_milestone=include_milestone,
489
+ min_version=parsed_min_version,
490
+ max_version=parsed_max_version,
491
+ except_versions=parsed_except_versions,
492
+ ):
493
+ integration_sessions_core = add_integration_tests(ansible_core_version)
494
+ if integration_sessions_core:
495
+ name = f"ansible-test-integration-{ansible_core_version}"
496
+ integration_sessions.append(name)
497
+
498
+ def run_integration_tests(
499
+ session: nox.Session, # pylint: disable=unused-argument
500
+ ) -> None:
501
+ pass
502
+
503
+ run_integration_tests.__doc__ = (
504
+ f"Meta session for running all {name}-* sessions."
505
+ )
506
+ nox.session(
507
+ name=name,
508
+ requires=integration_sessions_core,
509
+ default=False,
510
+ )(run_integration_tests)
511
+ if add_devel_like_branches:
512
+ for repo_name, branch_name in add_devel_like_branches:
513
+ integration_sessions_core = add_integration_tests(
514
+ "devel", repo_name=repo_name, branch_name=branch_name
515
+ )
516
+ if integration_sessions_core:
517
+ repo_prefix = (
518
+ f"{repo_name.replace('/', '-')}-" if repo_name is not None else ""
519
+ )
520
+ name = f"ansible-test-integration-{repo_prefix}{branch_name.replace('/', '-')}"
521
+ integration_sessions.append(name)
522
+
523
+ def run_integration_tests_for_branch(
524
+ session: nox.Session, # pylint: disable=unused-argument
525
+ ) -> None:
526
+ pass
527
+
528
+ run_integration_tests_for_branch.__doc__ = (
529
+ f"Meta session for running all {name}-* sessions."
530
+ )
531
+ nox.session(
532
+ name=name,
533
+ requires=integration_sessions_core,
534
+ default=False,
535
+ )(run_integration_tests_for_branch)
536
+
537
+ def ansible_test_integration(
538
+ session: nox.Session, # pylint: disable=unused-argument
539
+ ) -> None:
540
+ pass
541
+
542
+ ansible_test_integration.__doc__ = (
543
+ "Meta session for running all ansible-test-integration-* sessions."
544
+ )
545
+ nox.session(
546
+ name="ansible-test-integration",
547
+ requires=integration_sessions,
548
+ default=default,
549
+ )(ansible_test_integration)
550
+
551
+
552
+ __all__ = [
553
+ "add_ansible_test_session",
554
+ "add_ansible_test_sanity_test_session",
555
+ "add_all_ansible_test_sanity_test_sessions",
556
+ "add_ansible_test_unit_test_session",
557
+ "add_all_ansible_test_unit_test_sessions",
558
+ "add_ansible_test_integration_sessions_default_container",
559
+ ]
@@ -0,0 +1,147 @@
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 build import check session.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import os
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ import nox
18
+
19
+ from ..collection import (
20
+ force_collection_version,
21
+ load_collection_data_from_disk,
22
+ )
23
+ from ..paths import (
24
+ copy_collection,
25
+ remove_path,
26
+ )
27
+ from .utils import (
28
+ ci_group,
29
+ compose_description,
30
+ install,
31
+ nox_has_verbosity,
32
+ silence_run_verbosity,
33
+ )
34
+
35
+
36
+ def add_build_import_check(
37
+ *,
38
+ make_build_import_check_default: bool = True,
39
+ ansible_core_package: str = "ansible-core",
40
+ run_galaxy_importer: bool = True,
41
+ galaxy_importer_package: str = "galaxy-importer",
42
+ galaxy_importer_config_path: (
43
+ str | os.PathLike | None
44
+ ) = None, # https://github.com/ansible/galaxy-importer#configuration
45
+ galaxy_importer_always_show_logs: bool = False,
46
+ ) -> None:
47
+ """
48
+ Add license-check session for license checks.
49
+ """
50
+
51
+ def compose_dependencies() -> list[str]:
52
+ deps = [ansible_core_package]
53
+ if run_galaxy_importer:
54
+ deps.append(galaxy_importer_package)
55
+ return deps
56
+
57
+ def build_import_check(session: nox.Session) -> None:
58
+ install(session, *compose_dependencies())
59
+
60
+ tmp = Path(session.create_tmp())
61
+ collection_dir = tmp / "collection"
62
+ remove_path(collection_dir)
63
+ copy_collection(Path.cwd(), collection_dir)
64
+
65
+ collection = load_collection_data_from_disk(
66
+ collection_dir, accept_manifest=False
67
+ )
68
+ version = collection.version
69
+ if not version:
70
+ version = "0.0.1"
71
+ force_collection_version(collection_dir, version=version)
72
+
73
+ with session.chdir(collection_dir):
74
+ build_ran = session.run("ansible-galaxy", "collection", "build") is not None
75
+
76
+ tarball = (
77
+ collection_dir
78
+ / f"{collection.namespace}-{collection.name}-{version}.tar.gz"
79
+ )
80
+ if build_ran and not tarball.is_file():
81
+ files = "\n".join(
82
+ f"* {path.name}"
83
+ for path in collection_dir.iterdir()
84
+ if not path.is_dir()
85
+ )
86
+ session.error(f"Cannot find file {tarball}! List of all files:\n{files}")
87
+
88
+ if run_galaxy_importer and tarball.is_file():
89
+ env = {}
90
+ if galaxy_importer_config_path:
91
+ env["GALAXY_IMPORTER_CONFIG"] = str(
92
+ Path(galaxy_importer_config_path).absolute()
93
+ )
94
+ with session.chdir(collection_dir), silence_run_verbosity():
95
+ import_log = session.run(
96
+ "python",
97
+ "-m",
98
+ "galaxy_importer.main",
99
+ tarball.name,
100
+ env=env,
101
+ silent=True,
102
+ )
103
+ if import_log is not None:
104
+ with ci_group("Run Galaxy importer") as (indent, is_collapsed):
105
+ if (
106
+ is_collapsed
107
+ or galaxy_importer_always_show_logs
108
+ or nox_has_verbosity()
109
+ ):
110
+ for line in import_log.splitlines():
111
+ print(f"{indent}{line}")
112
+ sys.stdout.flush()
113
+ error_prefix = "ERROR:"
114
+ errors = []
115
+ for line in import_log.splitlines():
116
+ if line.startswith(error_prefix):
117
+ errors.append(line[len(error_prefix) :].strip())
118
+ if errors:
119
+ messages = "\n".join(f"* {error}" for error in errors)
120
+ session.warn(
121
+ "Galaxy importer emitted the following non-fatal"
122
+ f" error{'' if len(errors) == 1 else 's'}:\n{messages}"
123
+ )
124
+
125
+ build_import_check.__doc__ = compose_description(
126
+ prefix={
127
+ "one": "Run build and import checker:",
128
+ "other": "Run build and import checkers:",
129
+ },
130
+ programs={
131
+ "build-collection": True,
132
+ "galaxy-importer": (
133
+ "test whether Galaxy will import built collection"
134
+ if run_galaxy_importer
135
+ else False
136
+ ),
137
+ },
138
+ )
139
+ nox.session(
140
+ name="build-import-check",
141
+ default=make_build_import_check_default,
142
+ )(build_import_check)
143
+
144
+
145
+ __all__ = [
146
+ "add_build_import_check",
147
+ ]