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.
- antsibull_nox/__init__.py +7 -51
- antsibull_nox/_pydantic.py +98 -0
- antsibull_nox/cli.py +132 -0
- antsibull_nox/collection/__init__.py +2 -2
- antsibull_nox/collection/search.py +8 -4
- antsibull_nox/config.py +48 -2
- antsibull_nox/data/action-groups.py +2 -2
- antsibull_nox/data/antsibull-nox-lint-config.py +29 -0
- antsibull_nox/data/license-check.py +5 -1
- antsibull_nox/data/plugin-yamllint.py +3 -0
- antsibull_nox/init.py +83 -0
- antsibull_nox/interpret_config.py +17 -8
- antsibull_nox/lint_config.py +113 -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-0.2.0.dist-info → antsibull_nox-0.3.0.dist-info}/METADATA +2 -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/sessions.py +0 -1712
- antsibull_nox-0.2.0.dist-info/RECORD +0 -25
- {antsibull_nox-0.2.0.dist-info → antsibull_nox-0.3.0.dist-info}/WHEEL +0 -0
- {antsibull_nox-0.2.0.dist-info → antsibull_nox-0.3.0.dist-info}/licenses/LICENSES/GPL-3.0-or-later.txt +0 -0
antsibull_nox/__init__.py
CHANGED
@@ -10,71 +10,27 @@ Antsibull Nox Helper.
|
|
10
10
|
|
11
11
|
from __future__ import annotations
|
12
12
|
|
13
|
-
from .
|
14
|
-
|
15
|
-
|
16
|
-
from .sessions import (
|
17
|
-
ActionGroup,
|
18
|
-
add_all_ansible_test_sanity_test_sessions,
|
19
|
-
add_all_ansible_test_unit_test_sessions,
|
20
|
-
add_ansible_lint,
|
21
|
-
add_ansible_test_integration_sessions_default_container,
|
22
|
-
add_ansible_test_sanity_test_session,
|
23
|
-
add_ansible_test_session,
|
24
|
-
add_ansible_test_unit_test_session,
|
25
|
-
add_build_import_check,
|
26
|
-
add_docs_check,
|
27
|
-
add_extra_checks,
|
28
|
-
add_license_check,
|
29
|
-
add_lint_sessions,
|
30
|
-
add_matrix_generator,
|
13
|
+
from .config import (
|
14
|
+
CONFIG_FILENAME,
|
15
|
+
load_config_from_toml,
|
31
16
|
)
|
17
|
+
from .interpret_config import interpret_config
|
18
|
+
from .sessions.ansible_test import add_ansible_test_session
|
32
19
|
|
33
|
-
__version__ = "0.
|
34
|
-
|
35
|
-
|
36
|
-
def setup(
|
37
|
-
*,
|
38
|
-
collection_sources: dict[str, str | CollectionSource] | None = None,
|
39
|
-
) -> None:
|
40
|
-
"""
|
41
|
-
Set-up antsibull-nox.
|
42
|
-
"""
|
43
|
-
if collection_sources:
|
44
|
-
setup_collection_sources(
|
45
|
-
{
|
46
|
-
name: CollectionSource.parse(name, source)
|
47
|
-
for name, source in collection_sources.items()
|
48
|
-
}
|
49
|
-
)
|
20
|
+
__version__ = "0.3.0"
|
50
21
|
|
51
22
|
|
52
23
|
def load_antsibull_nox_toml() -> None:
|
53
24
|
"""
|
54
25
|
Load and interpret antsibull-nox.toml config file.
|
55
26
|
"""
|
56
|
-
config = load_config_from_toml(
|
27
|
+
config = load_config_from_toml(CONFIG_FILENAME)
|
57
28
|
interpret_config(config)
|
58
29
|
|
59
30
|
|
60
31
|
# pylint:disable=duplicate-code
|
61
32
|
__all__ = (
|
62
33
|
"__version__",
|
63
|
-
"ActionGroup",
|
64
|
-
"add_build_import_check",
|
65
|
-
"add_docs_check",
|
66
|
-
"add_extra_checks",
|
67
|
-
"add_license_check",
|
68
|
-
"add_lint_sessions",
|
69
34
|
"add_ansible_test_session",
|
70
|
-
"add_ansible_test_sanity_test_session",
|
71
|
-
"add_all_ansible_test_sanity_test_sessions",
|
72
|
-
"add_ansible_test_unit_test_session",
|
73
|
-
"add_all_ansible_test_unit_test_sessions",
|
74
|
-
"add_ansible_test_integration_sessions_default_container",
|
75
|
-
"add_ansible_lint",
|
76
|
-
"add_matrix_generator",
|
77
|
-
"CollectionSource",
|
78
|
-
"setup",
|
79
35
|
"load_antsibull_nox_toml",
|
80
36
|
)
|
@@ -0,0 +1,98 @@
|
|
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: Ansible Project, 2024
|
6
|
+
|
7
|
+
# ========================================================================
|
8
|
+
# **Vendored** from antsibull-core.
|
9
|
+
#
|
10
|
+
# I vendored this to avoid depending on antsibull-core only for this.
|
11
|
+
# TBH, most of this should be part of pydantic anyway. See
|
12
|
+
# https://github.com/pydantic/pydantic/discussions/2652 for a discussion
|
13
|
+
# on this.
|
14
|
+
#
|
15
|
+
# pylint: disable=missing-function-docstring
|
16
|
+
# ========================================================================
|
17
|
+
|
18
|
+
"""
|
19
|
+
Helpers for pydantic.
|
20
|
+
"""
|
21
|
+
|
22
|
+
from __future__ import annotations
|
23
|
+
|
24
|
+
import typing as t
|
25
|
+
from collections.abc import Callable, Collection
|
26
|
+
|
27
|
+
import pydantic as p
|
28
|
+
|
29
|
+
if t.TYPE_CHECKING:
|
30
|
+
from typing_extensions import TypeGuard
|
31
|
+
|
32
|
+
|
33
|
+
def _is_basemodel(a_type: t.Any) -> TypeGuard[type[p.BaseModel]]:
|
34
|
+
try:
|
35
|
+
return issubclass(a_type, p.BaseModel)
|
36
|
+
except TypeError:
|
37
|
+
# If inspect.isclass(a_type) is checked first, no TypeError happens for
|
38
|
+
# Python 3.11+.
|
39
|
+
|
40
|
+
# On Python 3.9 and 3.10, issubclass(dict[int, int], p.BaseModel) raises
|
41
|
+
# "TypeError: issubclass() arg 1 must be a class".
|
42
|
+
# (https://github.com/pydantic/pydantic/discussions/5970)
|
43
|
+
return False
|
44
|
+
|
45
|
+
|
46
|
+
def _modify_config(
|
47
|
+
cls: type[p.BaseModel],
|
48
|
+
processed_classes: set[type[p.BaseModel]],
|
49
|
+
change_config: Callable[[p.ConfigDict], bool],
|
50
|
+
) -> bool:
|
51
|
+
if cls in processed_classes:
|
52
|
+
return False
|
53
|
+
change = False
|
54
|
+
for field_info in cls.model_fields.values():
|
55
|
+
if _is_basemodel(field_info.annotation):
|
56
|
+
change |= _modify_config(
|
57
|
+
field_info.annotation,
|
58
|
+
processed_classes,
|
59
|
+
change_config,
|
60
|
+
)
|
61
|
+
for subcls in t.get_args(field_info.annotation):
|
62
|
+
if _is_basemodel(subcls):
|
63
|
+
change |= _modify_config(subcls, processed_classes, change_config)
|
64
|
+
change |= change_config(cls.model_config)
|
65
|
+
if change:
|
66
|
+
cls.model_rebuild(force=True)
|
67
|
+
processed_classes.add(cls)
|
68
|
+
return change
|
69
|
+
|
70
|
+
|
71
|
+
def set_extras(
|
72
|
+
models: type[p.BaseModel] | Collection[type[p.BaseModel]],
|
73
|
+
value: t.Literal["allow", "ignore", "forbid"],
|
74
|
+
) -> None:
|
75
|
+
def change_config(model_config: p.ConfigDict) -> bool:
|
76
|
+
if model_config.get("extra") == value:
|
77
|
+
return False
|
78
|
+
model_config["extra"] = value
|
79
|
+
return True
|
80
|
+
|
81
|
+
processed_classes: set[type[p.BaseModel]] = set()
|
82
|
+
if isinstance(models, Collection):
|
83
|
+
for cls in models:
|
84
|
+
_modify_config(cls, processed_classes, change_config)
|
85
|
+
else:
|
86
|
+
_modify_config(models, processed_classes, change_config)
|
87
|
+
|
88
|
+
|
89
|
+
def forbid_extras(models: type[p.BaseModel] | Collection[type[p.BaseModel]]) -> None:
|
90
|
+
set_extras(models, "forbid")
|
91
|
+
|
92
|
+
|
93
|
+
def get_formatted_error_messages(error: p.ValidationError) -> list[str]:
|
94
|
+
def format_error(err) -> str:
|
95
|
+
location = " -> ".join(str(loc) for loc in err["loc"])
|
96
|
+
return f'{location}: {err["msg"]}'
|
97
|
+
|
98
|
+
return [format_error(err) for err in error.errors()]
|
antsibull_nox/cli.py
ADDED
@@ -0,0 +1,132 @@
|
|
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
|
+
# PYTHON_ARGCOMPLETE_OK
|
8
|
+
|
9
|
+
"""Entrypoint to the antsibull-docs script."""
|
10
|
+
|
11
|
+
from __future__ import annotations
|
12
|
+
|
13
|
+
import argparse
|
14
|
+
import os
|
15
|
+
import os.path
|
16
|
+
import sys
|
17
|
+
from collections.abc import Callable
|
18
|
+
|
19
|
+
from . import __version__
|
20
|
+
from .init import create_initial_config as _create_initial_config
|
21
|
+
from .lint_config import lint_config as _lint_config
|
22
|
+
|
23
|
+
try:
|
24
|
+
import argcomplete
|
25
|
+
|
26
|
+
HAS_ARGCOMPLETE = True
|
27
|
+
except ImportError:
|
28
|
+
HAS_ARGCOMPLETE = False
|
29
|
+
|
30
|
+
|
31
|
+
def lint_config(_: argparse.Namespace) -> int:
|
32
|
+
"""
|
33
|
+
Lint antsibull-nox config file.
|
34
|
+
"""
|
35
|
+
errors = _lint_config()
|
36
|
+
for error in errors:
|
37
|
+
print(error)
|
38
|
+
return 0 if len(errors) == 0 else 3
|
39
|
+
|
40
|
+
|
41
|
+
def create_initial_config(_: argparse.Namespace) -> int:
|
42
|
+
"""
|
43
|
+
Create noxfile.py and antsibull-nox.toml.
|
44
|
+
"""
|
45
|
+
try:
|
46
|
+
_create_initial_config()
|
47
|
+
except Exception as exc: # pylint: disable=broad-exception-caught
|
48
|
+
print(f"Error: {exc}", file=sys.stderr)
|
49
|
+
return 3
|
50
|
+
return 0
|
51
|
+
|
52
|
+
|
53
|
+
# Mapping from command line subcommand names to functions which implement those.
|
54
|
+
# The functions need to take a single argument, the processed list of args.
|
55
|
+
ARGS_MAP: dict[str, Callable[[argparse.Namespace], int]] = {
|
56
|
+
"lint-config": lint_config,
|
57
|
+
"init": create_initial_config,
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
class InvalidArgumentError(Exception):
|
62
|
+
"""
|
63
|
+
Error while parsing arguments.
|
64
|
+
"""
|
65
|
+
|
66
|
+
|
67
|
+
def parse_args(program_name: str, args: list[str]) -> argparse.Namespace:
|
68
|
+
"""
|
69
|
+
Parse the command line arguments.
|
70
|
+
"""
|
71
|
+
|
72
|
+
toplevel_parser = argparse.ArgumentParser(
|
73
|
+
prog=program_name,
|
74
|
+
description="Script to manage generated documentation for ansible",
|
75
|
+
)
|
76
|
+
toplevel_parser.add_argument(
|
77
|
+
"--version",
|
78
|
+
action="version",
|
79
|
+
version=__version__,
|
80
|
+
help="Print the antsibull-nox version",
|
81
|
+
)
|
82
|
+
subparsers = toplevel_parser.add_subparsers(
|
83
|
+
title="Subcommands", dest="command", help="for help use: `SUBCOMMANDS -h`"
|
84
|
+
)
|
85
|
+
subparsers.required = True
|
86
|
+
|
87
|
+
subparsers.add_parser(
|
88
|
+
"lint-config",
|
89
|
+
description="Lint antsibull-nox configuration file",
|
90
|
+
)
|
91
|
+
|
92
|
+
subparsers.add_parser(
|
93
|
+
"init",
|
94
|
+
description="Create noxfile and antsibull-nox configuration file",
|
95
|
+
)
|
96
|
+
|
97
|
+
# This must come after all parser setup
|
98
|
+
if HAS_ARGCOMPLETE:
|
99
|
+
argcomplete.autocomplete(toplevel_parser)
|
100
|
+
|
101
|
+
parsed_args: argparse.Namespace = toplevel_parser.parse_args(args)
|
102
|
+
return parsed_args
|
103
|
+
|
104
|
+
|
105
|
+
def run(args: list[str]) -> int:
|
106
|
+
"""
|
107
|
+
Run the program.
|
108
|
+
"""
|
109
|
+
program_name = os.path.basename(args[0])
|
110
|
+
try:
|
111
|
+
parsed_args: argparse.Namespace = parse_args(program_name, args[1:])
|
112
|
+
except InvalidArgumentError as e:
|
113
|
+
print(e, file=sys.stderr)
|
114
|
+
return 2
|
115
|
+
|
116
|
+
return ARGS_MAP[parsed_args.command](parsed_args)
|
117
|
+
|
118
|
+
|
119
|
+
def main() -> int:
|
120
|
+
"""
|
121
|
+
Entrypoint called from the script.
|
122
|
+
|
123
|
+
Return codes:
|
124
|
+
:0: Success
|
125
|
+
:1: Unhandled error. See the Traceback for more information.
|
126
|
+
:2: There was a problem with the command line arguments
|
127
|
+
"""
|
128
|
+
return run(sys.argv)
|
129
|
+
|
130
|
+
|
131
|
+
if __name__ == "__main__":
|
132
|
+
sys.exit(main())
|
@@ -21,7 +21,7 @@ from .install import (
|
|
21
21
|
setup_collections,
|
22
22
|
setup_current_tree,
|
23
23
|
)
|
24
|
-
from .search import CollectionList, load_collection_data_from_disk
|
24
|
+
from .search import GALAXY_YML, CollectionList, load_collection_data_from_disk
|
25
25
|
|
26
26
|
|
27
27
|
def force_collection_version(path: Path, *, version: str) -> bool:
|
@@ -31,7 +31,7 @@ def force_collection_version(path: Path, *, version: str) -> bool:
|
|
31
31
|
Returns ``True`` if the version was changed, and ``False`` if the version
|
32
32
|
was already set to this value.
|
33
33
|
"""
|
34
|
-
galaxy_yml = path /
|
34
|
+
galaxy_yml = path / GALAXY_YML
|
35
35
|
try:
|
36
36
|
data = load_yaml_file(galaxy_yml)
|
37
37
|
except Exception as exc:
|
@@ -28,6 +28,10 @@ from .data import CollectionData
|
|
28
28
|
Runner = t.Callable[[list[str]], tuple[bytes, bytes]]
|
29
29
|
|
30
30
|
|
31
|
+
GALAXY_YML = "galaxy.yml"
|
32
|
+
MANIFEST_JSON = "MANIFEST.json"
|
33
|
+
|
34
|
+
|
31
35
|
@dataclass(frozen=True)
|
32
36
|
class _GlobalCache:
|
33
37
|
root: Path
|
@@ -80,19 +84,19 @@ def load_collection_data_from_disk(
|
|
80
84
|
"""
|
81
85
|
Load collection data from disk.
|
82
86
|
"""
|
83
|
-
galaxy_yml = path /
|
84
|
-
manifest_json = path /
|
87
|
+
galaxy_yml = path / GALAXY_YML
|
88
|
+
manifest_json = path / MANIFEST_JSON
|
85
89
|
found: Path
|
86
90
|
if galaxy_yml.is_file():
|
87
91
|
found = galaxy_yml
|
88
92
|
data = _load_galaxy_yml(galaxy_yml)
|
89
93
|
elif not accept_manifest:
|
90
|
-
raise ValueError(f"Cannot find
|
94
|
+
raise ValueError(f"Cannot find {GALAXY_YML} in {path}")
|
91
95
|
elif manifest_json.is_file():
|
92
96
|
found = manifest_json
|
93
97
|
data = _load_manifest_json_collection_info(manifest_json)
|
94
98
|
else:
|
95
|
-
raise ValueError(f"Cannot find
|
99
|
+
raise ValueError(f"Cannot find {GALAXY_YML} or {MANIFEST_JSON} in {path}")
|
96
100
|
|
97
101
|
ns = data.get("namespace")
|
98
102
|
if not isinstance(ns, str):
|
antsibull_nox/config.py
CHANGED
@@ -15,6 +15,7 @@ import typing as t
|
|
15
15
|
|
16
16
|
import pydantic as p
|
17
17
|
|
18
|
+
from ._pydantic import forbid_extras, get_formatted_error_messages
|
18
19
|
from .ansible import AnsibleCoreVersion
|
19
20
|
from .utils import Version
|
20
21
|
|
@@ -24,6 +25,9 @@ except ImportError:
|
|
24
25
|
from tomli import load as _load_toml # type: ignore
|
25
26
|
|
26
27
|
|
28
|
+
CONFIG_FILENAME = "antsibull-nox.toml"
|
29
|
+
|
30
|
+
|
27
31
|
def _parse_version(value: t.Any) -> Version:
|
28
32
|
if isinstance(value, Version):
|
29
33
|
return value
|
@@ -45,6 +49,18 @@ def _parse_ansible_core_version(value: t.Any) -> AnsibleCoreVersion:
|
|
45
49
|
raise ValueError("Must be ansible-core version string")
|
46
50
|
|
47
51
|
|
52
|
+
def _validate_collection_name(value: str) -> str:
|
53
|
+
parts = value.split(".")
|
54
|
+
if len(parts) != 2:
|
55
|
+
raise ValueError("Collection name must be of the form '<namespace>.<name>'")
|
56
|
+
if not parts[0].isidentifier():
|
57
|
+
raise ValueError("Collection namespace must be Python identifier")
|
58
|
+
if not parts[1].isidentifier():
|
59
|
+
raise ValueError("Collection name must be Python identifier")
|
60
|
+
return value
|
61
|
+
|
62
|
+
|
63
|
+
CollectionName = t.Annotated[str, p.AfterValidator(_validate_collection_name)]
|
48
64
|
PVersion = t.Annotated[Version, p.BeforeValidator(_parse_version)]
|
49
65
|
PAnsibleCoreVersion = t.Annotated[
|
50
66
|
AnsibleCoreVersion, p.BeforeValidator(_parse_ansible_core_version)
|
@@ -101,6 +117,9 @@ class SessionLint(_BaseModel):
|
|
101
117
|
mypy_ansible_core_package: t.Optional[str] = "ansible-core"
|
102
118
|
mypy_extra_deps: list[str] = []
|
103
119
|
|
120
|
+
# antsibull-nox config lint:
|
121
|
+
run_antsibullnox_config_lint: bool = True
|
122
|
+
|
104
123
|
|
105
124
|
class SessionDocsCheck(_BaseModel):
|
106
125
|
"""
|
@@ -112,7 +131,7 @@ class SessionDocsCheck(_BaseModel):
|
|
112
131
|
antsibull_docs_package: str = "antsibull-docs"
|
113
132
|
ansible_core_package: str = "ansible-core"
|
114
133
|
validate_collection_refs: t.Optional[t.Literal["self", "dependent", "all"]] = None
|
115
|
-
extra_collections: list[
|
134
|
+
extra_collections: list[CollectionName] = []
|
116
135
|
|
117
136
|
|
118
137
|
class SessionLicenseCheck(_BaseModel):
|
@@ -183,6 +202,7 @@ class SessionBuildImportCheck(_BaseModel):
|
|
183
202
|
galaxy_importer_package: str = "galaxy-importer"
|
184
203
|
# https://github.com/ansible/galaxy-importer#configuration
|
185
204
|
galaxy_importer_config_path: t.Optional[p.FilePath] = None
|
205
|
+
galaxy_importer_always_show_logs: bool = False
|
186
206
|
|
187
207
|
|
188
208
|
class DevelLikeBranch(_BaseModel):
|
@@ -220,6 +240,9 @@ class SessionAnsibleTestSanity(_BaseModel):
|
|
220
240
|
min_version: t.Optional[PVersion] = None
|
221
241
|
max_version: t.Optional[PVersion] = None
|
222
242
|
except_versions: list[PAnsibleCoreVersion] = []
|
243
|
+
skip_tests: list[str] = []
|
244
|
+
allow_disabled: bool = False
|
245
|
+
enable_optional_errors: bool = False
|
223
246
|
|
224
247
|
|
225
248
|
class SessionAnsibleTestUnits(_BaseModel):
|
@@ -316,7 +339,7 @@ class Config(_BaseModel):
|
|
316
339
|
The contents of a antsibull-nox config file.
|
317
340
|
"""
|
318
341
|
|
319
|
-
collection_sources: dict[
|
342
|
+
collection_sources: dict[CollectionName, CollectionSource] = {}
|
320
343
|
sessions: Sessions = Sessions()
|
321
344
|
|
322
345
|
|
@@ -330,3 +353,26 @@ def load_config_from_toml(path: str | os.PathLike) -> Config:
|
|
330
353
|
except ValueError as exc:
|
331
354
|
raise ValueError(f"Error while reading {path}: {exc}") from exc
|
332
355
|
return Config.model_validate(data)
|
356
|
+
|
357
|
+
|
358
|
+
def lint_config_toml() -> list[str]:
|
359
|
+
"""
|
360
|
+
Lint config files
|
361
|
+
"""
|
362
|
+
path = CONFIG_FILENAME
|
363
|
+
errors = []
|
364
|
+
forbid_extras(Config)
|
365
|
+
try:
|
366
|
+
with open(path, "rb") as f:
|
367
|
+
data = _load_toml(f)
|
368
|
+
Config.model_validate(data)
|
369
|
+
except p.ValidationError as exc:
|
370
|
+
for error in get_formatted_error_messages(exc):
|
371
|
+
errors.append(f"{path}:{error}")
|
372
|
+
except ValueError as exc:
|
373
|
+
errors.append(f"{path}:{exc}")
|
374
|
+
except FileNotFoundError:
|
375
|
+
errors.append(f"{path}: File does not exist")
|
376
|
+
except IOError as exc:
|
377
|
+
errors.append(f"{path}:{exc}")
|
378
|
+
return errors
|
@@ -17,7 +17,7 @@ import typing as t
|
|
17
17
|
import yaml
|
18
18
|
|
19
19
|
from antsibull_nox.data.antsibull_nox_data_util import setup
|
20
|
-
from antsibull_nox.sessions import ActionGroup
|
20
|
+
from antsibull_nox.sessions.extra_checks import ActionGroup
|
21
21
|
|
22
22
|
|
23
23
|
def compile_patterns(
|
@@ -41,7 +41,7 @@ def load_redirects(
|
|
41
41
|
try:
|
42
42
|
with open(meta_runtime, "rb") as f:
|
43
43
|
data = yaml.safe_load(f)
|
44
|
-
action_groups = data
|
44
|
+
action_groups = data.get("action_groups", {})
|
45
45
|
except Exception as exc:
|
46
46
|
errors.append(f"{meta_runtime}: cannot load action groups: {exc}")
|
47
47
|
return {}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
# Copyright (c) 2025, Felix Fontein <felix@fontein.de>
|
4
|
+
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt
|
5
|
+
# or https://www.gnu.org/licenses/gpl-3.0.txt)
|
6
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
7
|
+
|
8
|
+
"""Run antsibull-nox lint-config."""
|
9
|
+
|
10
|
+
from __future__ import annotations
|
11
|
+
|
12
|
+
import sys
|
13
|
+
|
14
|
+
from antsibull_nox.data.antsibull_nox_data_util import setup
|
15
|
+
from antsibull_nox.lint_config import lint_config
|
16
|
+
|
17
|
+
|
18
|
+
def main() -> int:
|
19
|
+
"""Main entry point."""
|
20
|
+
_, __ = setup()
|
21
|
+
|
22
|
+
errors = lint_config()
|
23
|
+
for error in errors:
|
24
|
+
print(error)
|
25
|
+
return len(errors) > 0
|
26
|
+
|
27
|
+
|
28
|
+
if __name__ == "__main__":
|
29
|
+
sys.exit(main())
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
11
11
|
|
12
12
|
import glob
|
13
13
|
import os
|
14
|
+
import stat
|
14
15
|
import sys
|
15
16
|
|
16
17
|
from antsibull_nox.data.antsibull_nox_data_util import get_list_of_strings, setup
|
@@ -108,7 +109,10 @@ def main() -> int:
|
|
108
109
|
path = path[2:]
|
109
110
|
if path in ignore_paths or path.startswith("tests/output/"):
|
110
111
|
continue
|
111
|
-
|
112
|
+
sr = os.stat(path)
|
113
|
+
if not stat.S_ISREG(sr.st_mode):
|
114
|
+
continue
|
115
|
+
if sr.st_size == 0:
|
112
116
|
continue
|
113
117
|
if not path.endswith(".license") and os.path.exists(path + ".license"):
|
114
118
|
path = path + ".license"
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
11
11
|
|
12
12
|
import ast
|
13
13
|
import io
|
14
|
+
import os
|
14
15
|
import re
|
15
16
|
import sys
|
16
17
|
import traceback
|
@@ -219,6 +220,8 @@ def main() -> int:
|
|
219
220
|
|
220
221
|
errors: list[dict[str, t.Any]] = []
|
221
222
|
for path in paths:
|
223
|
+
if not os.path.isfile(path):
|
224
|
+
continue
|
222
225
|
if path.endswith(".py"):
|
223
226
|
process_python_file(errors, path, yamllint_config, yamllint_config_examples)
|
224
227
|
if path.endswith((".yml", ".yaml")):
|
antsibull_nox/init.py
ADDED
@@ -0,0 +1,83 @@
|
|
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
|
+
"""Tool to create initial configuration."""
|
8
|
+
|
9
|
+
from pathlib import Path
|
10
|
+
|
11
|
+
from .collection.search import GALAXY_YML
|
12
|
+
from .config import CONFIG_FILENAME
|
13
|
+
from .lint_config import NOXFILE_PY
|
14
|
+
|
15
|
+
NOXFILE_CONTENT = r"""
|
16
|
+
# The following metadata allows Python runners and nox to install the required
|
17
|
+
# dependencies for running this Python script:
|
18
|
+
#
|
19
|
+
# /// script
|
20
|
+
# dependencies = ["nox>=2025.02.09", "antsibull-nox"]
|
21
|
+
# ///
|
22
|
+
|
23
|
+
import sys
|
24
|
+
|
25
|
+
import nox
|
26
|
+
|
27
|
+
|
28
|
+
# We try to import antsibull-nox, and if that doesn't work, provide a more useful
|
29
|
+
# error message to the user.
|
30
|
+
try:
|
31
|
+
import antsibull_nox
|
32
|
+
except ImportError:
|
33
|
+
print("You need to install antsibull-nox in the same Python environment as nox.")
|
34
|
+
sys.exit(1)
|
35
|
+
|
36
|
+
|
37
|
+
antsibull_nox.load_antsibull_nox_toml()
|
38
|
+
|
39
|
+
|
40
|
+
# Allow to run the noxfile with `python noxfile.py`, `pipx run noxfile.py`, or similar.
|
41
|
+
# Requires nox >= 2025.02.09
|
42
|
+
if __name__ == "__main__":
|
43
|
+
nox.main()
|
44
|
+
"""
|
45
|
+
|
46
|
+
CONFIG_CONTENT = r"""
|
47
|
+
[sessions]
|
48
|
+
|
49
|
+
[sessions.lint]
|
50
|
+
# disable reformatting for now
|
51
|
+
run_isort = false
|
52
|
+
|
53
|
+
# disable reformatting for now
|
54
|
+
run_black = false
|
55
|
+
|
56
|
+
# Add more configuration settings here to adjust to your collection;
|
57
|
+
# see https://ansible.readthedocs.io/projects/antsibull-nox/config-file/#basic-linting-sessions
|
58
|
+
|
59
|
+
[sessions.docs_check]
|
60
|
+
# Add configuration settings here to adjust to your collection;
|
61
|
+
# see https://ansible.readthedocs.io/projects/antsibull-nox/config-file/#collection-documentation-check
|
62
|
+
"""
|
63
|
+
|
64
|
+
|
65
|
+
def create_initial_config(*, path: Path | None = None) -> None:
|
66
|
+
"""
|
67
|
+
Write noxfile.py and antsibull-nox.toml for a collection.
|
68
|
+
"""
|
69
|
+
if path is None:
|
70
|
+
path = Path()
|
71
|
+
|
72
|
+
galaxy_yml = path / GALAXY_YML
|
73
|
+
if not galaxy_yml.is_file():
|
74
|
+
raise ValueError(f"Cannot find {galaxy_yml}")
|
75
|
+
|
76
|
+
noxfile = path / NOXFILE_PY
|
77
|
+
config_file = path / CONFIG_FILENAME
|
78
|
+
for file in (noxfile, config_file):
|
79
|
+
if file.exists():
|
80
|
+
raise ValueError(f"{file} already exists")
|
81
|
+
|
82
|
+
noxfile.write_text(NOXFILE_CONTENT)
|
83
|
+
config_file.write_text(CONFIG_CONTENT)
|
@@ -20,19 +20,21 @@ from .config import (
|
|
20
20
|
DevelLikeBranch,
|
21
21
|
Sessions,
|
22
22
|
)
|
23
|
-
from .sessions import
|
24
|
-
|
23
|
+
from .sessions import add_matrix_generator
|
24
|
+
from .sessions.ansible_lint import add_ansible_lint
|
25
|
+
from .sessions.ansible_test import (
|
25
26
|
add_all_ansible_test_sanity_test_sessions,
|
26
27
|
add_all_ansible_test_unit_test_sessions,
|
27
|
-
add_ansible_lint,
|
28
28
|
add_ansible_test_integration_sessions_default_container,
|
29
|
-
|
30
|
-
|
29
|
+
)
|
30
|
+
from .sessions.build_import_check import add_build_import_check
|
31
|
+
from .sessions.docs_check import add_docs_check
|
32
|
+
from .sessions.extra_checks import (
|
33
|
+
ActionGroup,
|
31
34
|
add_extra_checks,
|
32
|
-
add_license_check,
|
33
|
-
add_lint_sessions,
|
34
|
-
add_matrix_generator,
|
35
35
|
)
|
36
|
+
from .sessions.license_check import add_license_check
|
37
|
+
from .sessions.lint import add_lint_sessions
|
36
38
|
from .utils import Version
|
37
39
|
|
38
40
|
|
@@ -116,6 +118,7 @@ def _add_sessions(sessions: Sessions) -> None:
|
|
116
118
|
mypy_package=sessions.lint.mypy_package,
|
117
119
|
mypy_ansible_core_package=sessions.lint.mypy_ansible_core_package,
|
118
120
|
mypy_extra_deps=sessions.lint.mypy_extra_deps,
|
121
|
+
run_antsibullnox_config_lint=sessions.lint.run_antsibullnox_config_lint,
|
119
122
|
)
|
120
123
|
if sessions.docs_check:
|
121
124
|
add_docs_check(
|
@@ -172,6 +175,9 @@ def _add_sessions(sessions: Sessions) -> None:
|
|
172
175
|
run_galaxy_importer=sessions.build_import_check.run_galaxy_importer,
|
173
176
|
galaxy_importer_package=sessions.build_import_check.galaxy_importer_package,
|
174
177
|
galaxy_importer_config_path=sessions.build_import_check.galaxy_importer_config_path,
|
178
|
+
galaxy_importer_always_show_logs=(
|
179
|
+
sessions.build_import_check.galaxy_importer_always_show_logs
|
180
|
+
),
|
175
181
|
)
|
176
182
|
if sessions.ansible_test_sanity:
|
177
183
|
add_all_ansible_test_sanity_test_sessions(
|
@@ -186,6 +192,9 @@ def _add_sessions(sessions: Sessions) -> None:
|
|
186
192
|
except_versions=_convert_except_versions(
|
187
193
|
sessions.ansible_test_sanity.except_versions
|
188
194
|
),
|
195
|
+
skip_tests=sessions.ansible_test_sanity.skip_tests,
|
196
|
+
allow_disabled=sessions.ansible_test_sanity.allow_disabled,
|
197
|
+
enable_optional_errors=sessions.ansible_test_sanity.enable_optional_errors,
|
189
198
|
)
|
190
199
|
if sessions.ansible_test_units:
|
191
200
|
add_all_ansible_test_unit_test_sessions(
|