summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLee Garrett <lgarrett@rocketjump.eu>2023-07-17 14:21:21 +0200
committerLee Garrett <lgarrett@rocketjump.eu>2023-07-17 14:21:21 +0200
commita00ca87e07387d5be8152f7e1d2a69701f9949d6 (patch)
tree9f930fb63b5bda3aa8b40bb94b348a305ba9eb74
parent8d9a6d9cdf440b0a9b254a8a4bf063c0cb6a6201 (diff)
downloaddebian-ansible-core-a00ca87e07387d5be8152f7e1d2a69701f9949d6.zip
New upstream version 2.14.7
-rw-r--r--MANIFEST.in3
-rw-r--r--Makefile4
-rw-r--r--PKG-INFO2
-rw-r--r--changelogs/CHANGELOG-v2.14.rst23
-rw-r--r--changelogs/changelog.yaml38
-rw-r--r--docs/docsite/requirements.txt1
-rw-r--r--docs/docsite/sphinx_conf/core_conf.py4
-rw-r--r--docs/man/man1/ansible-config.12
-rw-r--r--docs/man/man1/ansible-console.12
-rw-r--r--docs/man/man1/ansible-doc.12
-rw-r--r--docs/man/man1/ansible-galaxy.12
-rw-r--r--docs/man/man1/ansible-inventory.12
-rw-r--r--docs/man/man1/ansible-playbook.12
-rw-r--r--docs/man/man1/ansible-pull.12
-rw-r--r--docs/man/man1/ansible-vault.12
-rw-r--r--docs/man/man1/ansible.12
-rwxr-xr-xhacking/build-ansible.py33
-rw-r--r--hacking/build_library/build_ansible/command_plugins/generate_man.py2
-rw-r--r--hacking/templates/man.j2 (renamed from docs/templates/man.j2)0
-rw-r--r--lib/ansible/module_utils/ansible_release.py2
-rw-r--r--lib/ansible/modules/uri.py10
-rw-r--r--lib/ansible/release.py2
-rw-r--r--lib/ansible_core.egg-info/PKG-INFO2
-rw-r--r--lib/ansible_core.egg-info/SOURCES.txt4
-rw-r--r--packaging/pep517_backend/_backend.py7
-rw-r--r--packaging/pep517_backend/_generate_man.py310
-rw-r--r--packaging/pep517_backend/_templates/man.j2128
-rw-r--r--test/integration/targets/canonical-pep517-self-packaging/minimum-build-constraints.txt1
-rw-r--r--test/integration/targets/canonical-pep517-self-packaging/modernish-build-constraints.txt1
-rw-r--r--test/integration/targets/uri/tasks/main.yml12
-rw-r--r--test/lib/ansible_test/_internal/data.py9
-rw-r--r--test/lib/ansible_test/_internal/git.py2
-rw-r--r--test/lib/ansible_test/_internal/provider/layout/__init__.py2
-rw-r--r--test/lib/ansible_test/_internal/provider/layout/ansible.py15
-rw-r--r--test/lib/ansible_test/_internal/provider/layout/collection.py10
35 files changed, 603 insertions, 42 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index 6c867365..566c2d66 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -29,7 +29,7 @@ recursive-include lib/ansible/modules *.yml
recursive-include lib/ansible/plugins/test *.yml
recursive-include lib/ansible/plugins/filter *.yml
recursive-include licenses *.txt
-recursive-include packaging Makefile *.py
+recursive-include packaging Makefile *.py *.j2
recursive-include test/ansible_test *.py Makefile
recursive-include test/integration *
recursive-include test/lib/ansible_test/config *.yml *.template
@@ -49,6 +49,7 @@ include changelogs/CHANGELOG*.rst
include changelogs/changelog.yaml
recursive-include hacking/build_library *.py
include hacking/build-ansible.py
+include hacking/templates/*.j2
include hacking/test-module.py
include hacking/update-sanity-requirements.py
include bin/*
diff --git a/Makefile b/Makefile
index 079386b0..1b72ea82 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ ASCII2MAN = @echo "ERROR: rst2man from docutils command is not installed but is
endif
PYTHON ?= python
-GENERATE_CLI = hacking/build-ansible.py generate-man
+GENERATE_CLI = packaging/pep517_backend/_generate_man.py
# fetch version from project release.py as single source-of-truth
VERSION := $(shell $(PYTHON) packaging/release/versionhelper/version_helper.py --raw || echo error)
@@ -146,7 +146,7 @@ changelog:
.PHONY: generate_rst
generate_rst: lib/ansible/cli/*.py
mkdir -p ./docs/man/man1/ ; \
- $(PYTHON) $(GENERATE_CLI) --template-file=docs/templates/man.j2 --output-dir=docs/man/man1/ --output-format man lib/ansible/cli/*.py
+ $(PYTHON) $(GENERATE_CLI) --template-file=packaging/pep517_backend/_templates/man.j2 --output-dir=docs/man/man1/ --output-format man lib/ansible/cli/*.py
.PHONY: docs
docs: generate_rst
diff --git a/PKG-INFO b/PKG-INFO
index b625a17a..d2ff788a 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: ansible-core
-Version: 2.14.6
+Version: 2.14.7
Summary: Radically simple IT automation
Home-page: https://ansible.com/
Author: Ansible, Inc.
diff --git a/changelogs/CHANGELOG-v2.14.rst b/changelogs/CHANGELOG-v2.14.rst
index 51436b14..0c912e3b 100644
--- a/changelogs/CHANGELOG-v2.14.rst
+++ b/changelogs/CHANGELOG-v2.14.rst
@@ -5,6 +5,29 @@ ansible-core 2.14 "C'mon Everybody" Release Notes
.. contents:: Topics
+v2.14.7
+=======
+
+Release Summary
+---------------
+
+| Release Date: 2023-06-20
+| `Porting Guide <https://docs.ansible.com/ansible-core/2.14/porting_guides/porting_guide_core_2.14.html>`__
+
+
+Minor Changes
+-------------
+
+- Removed ``straight.plugin`` from the build and packaging requirements.
+
+Bugfixes
+--------
+
+- ansible-test - Fix a traceback that occurs when attempting to test Ansible source using a different ansible-test. A clear error message is now given when this scenario occurs.
+- ansible-test local change detection - use ``git merge-base <branch> HEAD`` instead of ``git merge-base --fork-point <branch>`` (https://github.com/ansible/ansible/pull/79734).
+- man page build - Remove the dependency on the ``docs`` directory for building man pages.
+- uri - fix search for JSON type to include complex strings containing '+'
+
v2.14.6
=======
diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml
index 18bf7b13..f0137291 100644
--- a/changelogs/changelog.yaml
+++ b/changelogs/changelog.yaml
@@ -1304,3 +1304,41 @@ releases:
- ansible-test-utcnow.yml
- pep517-backend-traceback-fix.yml
release_date: '2023-05-15'
+ 2.14.7:
+ changes:
+ release_summary: '| Release Date: 2023-06-20
+
+ | `Porting Guide <https://docs.ansible.com/ansible-core/2.14/porting_guides/porting_guide_core_2.14.html>`__
+
+ '
+ codename: C'mon Everybody
+ fragments:
+ - 2.14.7_summary.yaml
+ release_date: '2023-06-20'
+ 2.14.7rc1:
+ changes:
+ bugfixes:
+ - ansible-test - Fix a traceback that occurs when attempting to test Ansible
+ source using a different ansible-test. A clear error message is now given
+ when this scenario occurs.
+ - ansible-test local change detection - use ``git merge-base <branch> HEAD``
+ instead of ``git merge-base --fork-point <branch>`` (https://github.com/ansible/ansible/pull/79734).
+ - man page build - Remove the dependency on the ``docs`` directory for building
+ man pages.
+ - uri - fix search for JSON type to include complex strings containing '+'
+ minor_changes:
+ - Removed ``straight.plugin`` from the build and packaging requirements.
+ release_summary: '| Release Date: 2023-06-12
+
+ | `Porting Guide <https://docs.ansible.com/ansible-core/2.14/porting_guides/porting_guide_core_2.14.html>`__
+
+ '
+ codename: C'mon Everybody
+ fragments:
+ - 2.14.7rc1_summary.yaml
+ - 79734-ansible-test-change-detection.yml
+ - ansible-test-source-detection.yml
+ - build-no-straight.yaml
+ - man-page-build-docs-dependency.yml
+ - update-maybe-json-uri.yml
+ release_date: '2023-06-12'
diff --git a/docs/docsite/requirements.txt b/docs/docsite/requirements.txt
index 66e707c6..dac425da 100644
--- a/docs/docsite/requirements.txt
+++ b/docs/docsite/requirements.txt
@@ -15,4 +15,3 @@ sphinx-notfound-page >= 0.6
sphinx-intl
sphinx-ansible-theme >= 0.9.1
resolvelib
-straight.plugin # Needed for hacking/build-ansible.py which is the backend build script
diff --git a/docs/docsite/sphinx_conf/core_conf.py b/docs/docsite/sphinx_conf/core_conf.py
index a279c02f..a1ce0ee1 100644
--- a/docs/docsite/sphinx_conf/core_conf.py
+++ b/docs/docsite/sphinx_conf/core_conf.py
@@ -202,9 +202,9 @@ html_context = {
'github_root_dir': 'devel/lib/ansible',
'github_cli_version': 'devel/lib/ansible/cli/',
'current_version': version,
- 'latest_version': '2.14',
+ 'latest_version': '2.15',
# list specifically out of order to make latest work
- 'available_versions': ('2.14', '2.13', '2.12', 'devel',),
+ 'available_versions': ('2.15', '2.14', '2.13', 'devel',),
}
# Add extra CSS styles to the resulting HTML pages
diff --git a/docs/man/man1/ansible-config.1 b/docs/man/man1/ansible-config.1
index a5724586..009cb4ef 100644
--- a/docs/man/man1/ansible-config.1
+++ b/docs/man/man1/ansible-config.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "ANSIBLE-CONFIG" 1 "" "Ansible 2.14.6" "System administration commands"
+.TH "ANSIBLE-CONFIG" 1 "" "Ansible 2.14.7" "System administration commands"
.SH NAME
ansible-config \- View ansible configuration.
.SH SYNOPSIS
diff --git a/docs/man/man1/ansible-console.1 b/docs/man/man1/ansible-console.1
index 026ae8a5..9ee48cfe 100644
--- a/docs/man/man1/ansible-console.1
+++ b/docs/man/man1/ansible-console.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "ANSIBLE-CONSOLE" 1 "" "Ansible 2.14.6" "System administration commands"
+.TH "ANSIBLE-CONSOLE" 1 "" "Ansible 2.14.7" "System administration commands"
.SH NAME
ansible-console \- REPL console for executing Ansible tasks.
.SH SYNOPSIS
diff --git a/docs/man/man1/ansible-doc.1 b/docs/man/man1/ansible-doc.1
index 8c262a24..fd92c60b 100644
--- a/docs/man/man1/ansible-doc.1
+++ b/docs/man/man1/ansible-doc.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "ANSIBLE-DOC" 1 "" "Ansible 2.14.6" "System administration commands"
+.TH "ANSIBLE-DOC" 1 "" "Ansible 2.14.7" "System administration commands"
.SH NAME
ansible-doc \- plugin documentation tool
.SH SYNOPSIS
diff --git a/docs/man/man1/ansible-galaxy.1 b/docs/man/man1/ansible-galaxy.1
index 36d42830..8ed2713a 100644
--- a/docs/man/man1/ansible-galaxy.1
+++ b/docs/man/man1/ansible-galaxy.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "ANSIBLE-GALAXY" 1 "" "Ansible 2.14.6" "System administration commands"
+.TH "ANSIBLE-GALAXY" 1 "" "Ansible 2.14.7" "System administration commands"
.SH NAME
ansible-galaxy \- Perform various Role and Collection related operations.
.SH SYNOPSIS
diff --git a/docs/man/man1/ansible-inventory.1 b/docs/man/man1/ansible-inventory.1
index e35df15c..eaff6ae0 100644
--- a/docs/man/man1/ansible-inventory.1
+++ b/docs/man/man1/ansible-inventory.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "ANSIBLE-INVENTORY" 1 "" "Ansible 2.14.6" "System administration commands"
+.TH "ANSIBLE-INVENTORY" 1 "" "Ansible 2.14.7" "System administration commands"
.SH NAME
ansible-inventory \- None
.SH SYNOPSIS
diff --git a/docs/man/man1/ansible-playbook.1 b/docs/man/man1/ansible-playbook.1
index 82f0599e..412e1ace 100644
--- a/docs/man/man1/ansible-playbook.1
+++ b/docs/man/man1/ansible-playbook.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "ANSIBLE-PLAYBOOK" 1 "" "Ansible 2.14.6" "System administration commands"
+.TH "ANSIBLE-PLAYBOOK" 1 "" "Ansible 2.14.7" "System administration commands"
.SH NAME
ansible-playbook \- Runs Ansible playbooks, executing the defined tasks on the targeted hosts.
.SH SYNOPSIS
diff --git a/docs/man/man1/ansible-pull.1 b/docs/man/man1/ansible-pull.1
index bafa0193..46b6099b 100644
--- a/docs/man/man1/ansible-pull.1
+++ b/docs/man/man1/ansible-pull.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "ANSIBLE-PULL" 1 "" "Ansible 2.14.6" "System administration commands"
+.TH "ANSIBLE-PULL" 1 "" "Ansible 2.14.7" "System administration commands"
.SH NAME
ansible-pull \- pulls playbooks from a VCS repo and executes them for the local host
.SH SYNOPSIS
diff --git a/docs/man/man1/ansible-vault.1 b/docs/man/man1/ansible-vault.1
index 4127214d..6bd3785b 100644
--- a/docs/man/man1/ansible-vault.1
+++ b/docs/man/man1/ansible-vault.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "ANSIBLE-VAULT" 1 "" "Ansible 2.14.6" "System administration commands"
+.TH "ANSIBLE-VAULT" 1 "" "Ansible 2.14.7" "System administration commands"
.SH NAME
ansible-vault \- encryption/decryption utility for Ansible data files
.SH SYNOPSIS
diff --git a/docs/man/man1/ansible.1 b/docs/man/man1/ansible.1
index 2d2a551c..51295aff 100644
--- a/docs/man/man1/ansible.1
+++ b/docs/man/man1/ansible.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "ANSIBLE" 1 "" "Ansible 2.14.6" "System administration commands"
+.TH "ANSIBLE" 1 "" "Ansible 2.14.7" "System administration commands"
.SH NAME
ansible \- Define and run a single task 'playbook' against a set of hosts
.SH SYNOPSIS
diff --git a/hacking/build-ansible.py b/hacking/build-ansible.py
index c108c186..717cf1c1 100755
--- a/hacking/build-ansible.py
+++ b/hacking/build-ansible.py
@@ -10,16 +10,20 @@ __metaclass__ = type
import argparse
+import importlib
+import inspect
import os.path
+import pkgutil
import sys
-
-from straight.plugin import load
+import typing as t
try:
import argcomplete
except ImportError:
argcomplete = None
+C = t.TypeVar('C')
+
def build_lib_path(this_script=__file__):
"""Return path to the common build library directory."""
@@ -55,6 +59,27 @@ def create_arg_parser(program_name):
return parser
+def load(package: str, subclasses: t.Type[C]) -> list[t.Type[C]]:
+ """Load modules in the specified package and return concrete types that derive from the specified base class."""
+ for module in pkgutil.iter_modules(importlib.import_module(package).__path__, f'{package}.'):
+ try:
+ importlib.import_module(module.name)
+ except ImportError:
+ pass # ignore plugins which are missing dependencies
+
+ types: set[t.Type[C]] = set()
+ queue: list[t.Type[C]] = [subclasses]
+
+ while queue:
+ for child in queue.pop().__subclasses__():
+ queue.append(child)
+
+ if not inspect.isabstract(child):
+ types.add(child)
+
+ return sorted(types, key=lambda sc: sc.__name__)
+
+
def main():
"""
Start our run.
@@ -69,7 +94,9 @@ def main():
help='Show tracebacks and other debugging information')
subparsers = arg_parser.add_subparsers(title='Subcommands', dest='command',
help='for help use build-ansible.py SUBCOMMANDS -h')
- subcommands.pipe('init_parser', subparsers.add_parser)
+
+ for subcommand in subcommands:
+ subcommand.init_parser(subparsers.add_parser)
if argcomplete:
argcomplete.autocomplete(arg_parser)
diff --git a/hacking/build_library/build_ansible/command_plugins/generate_man.py b/hacking/build_library/build_ansible/command_plugins/generate_man.py
index 3795c0d2..a8c668a0 100644
--- a/hacking/build_library/build_ansible/command_plugins/generate_man.py
+++ b/hacking/build_library/build_ansible/command_plugins/generate_man.py
@@ -21,7 +21,7 @@ from ..change_detection import update_file_if_different # pylint: disable=relat
from ..commands import Command # pylint: disable=relative-beyond-top-level
-DEFAULT_TEMPLATE_FILE = pathlib.Path(__file__).parents[4] / 'docs/templates/man.j2'
+DEFAULT_TEMPLATE_FILE = pathlib.Path(__file__).parents[4] / 'hacking/templates/man.j2'
# from https://www.python.org/dev/peps/pep-0257/
diff --git a/docs/templates/man.j2 b/hacking/templates/man.j2
index 8bd3644c..8bd3644c 100644
--- a/docs/templates/man.j2
+++ b/hacking/templates/man.j2
diff --git a/lib/ansible/module_utils/ansible_release.py b/lib/ansible/module_utils/ansible_release.py
index f59976b8..67de85c3 100644
--- a/lib/ansible/module_utils/ansible_release.py
+++ b/lib/ansible/module_utils/ansible_release.py
@@ -19,6 +19,6 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-__version__ = '2.14.6'
+__version__ = '2.14.7'
__author__ = 'Ansible, Inc.'
__codename__ = "C'mon Everybody"
diff --git a/lib/ansible/modules/uri.py b/lib/ansible/modules/uri.py
index 7919b9b2..9f01e1f7 100644
--- a/lib/ansible/modules/uri.py
+++ b/lib/ansible/modules/uri.py
@@ -706,7 +706,15 @@ def main():
sub_type = 'octet-stream'
content_encoding = 'utf-8'
- maybe_json = content_type and sub_type.lower() in JSON_CANDIDATES
+ if sub_type and '+' in sub_type:
+ # https://www.rfc-editor.org/rfc/rfc6839#section-3.1
+ sub_type_suffix = sub_type.partition('+')[2]
+ maybe_json = content_type and sub_type_suffix.lower() in JSON_CANDIDATES
+ elif sub_type:
+ maybe_json = content_type and sub_type.lower() in JSON_CANDIDATES
+ else:
+ maybe_json = False
+
maybe_output = maybe_json or return_content or info['status'] not in status_code
if maybe_output:
diff --git a/lib/ansible/release.py b/lib/ansible/release.py
index f59976b8..67de85c3 100644
--- a/lib/ansible/release.py
+++ b/lib/ansible/release.py
@@ -19,6 +19,6 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-__version__ = '2.14.6'
+__version__ = '2.14.7'
__author__ = 'Ansible, Inc.'
__codename__ = "C'mon Everybody"
diff --git a/lib/ansible_core.egg-info/PKG-INFO b/lib/ansible_core.egg-info/PKG-INFO
index b625a17a..d2ff788a 100644
--- a/lib/ansible_core.egg-info/PKG-INFO
+++ b/lib/ansible_core.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: ansible-core
-Version: 2.14.6
+Version: 2.14.7
Summary: Radically simple IT automation
Home-page: https://ansible.com/
Author: Ansible, Inc.
diff --git a/lib/ansible_core.egg-info/SOURCES.txt b/lib/ansible_core.egg-info/SOURCES.txt
index dd37d2ed..4e770d7c 100644
--- a/lib/ansible_core.egg-info/SOURCES.txt
+++ b/lib/ansible_core.egg-info/SOURCES.txt
@@ -642,7 +642,6 @@ docs/man/man3/.gitdir
docs/templates/cli_rst.j2
docs/templates/collections_galaxy_meta.rst.j2
docs/templates/config.rst.j2
-docs/templates/man.j2
docs/templates/modules_by_category.rst.j2
docs/templates/playbooks_keywords.rst.j2
examples/ansible.cfg
@@ -667,6 +666,7 @@ hacking/build_library/build_ansible/command_plugins/generate_man.py
hacking/build_library/build_ansible/command_plugins/porting_guide.py
hacking/build_library/build_ansible/command_plugins/release_announcement.py
hacking/build_library/build_ansible/command_plugins/update_intersphinx.py
+hacking/templates/man.j2
lib/ansible/__init__.py
lib/ansible/__main__.py
lib/ansible/constants.py
@@ -1357,7 +1357,9 @@ licenses/simplified_bsd.txt
packaging/release.py
packaging/pep517_backend/__init__.py
packaging/pep517_backend/_backend.py
+packaging/pep517_backend/_generate_man.py
packaging/pep517_backend/hooks.py
+packaging/pep517_backend/_templates/man.j2
packaging/release/Makefile
packaging/release/tests/__init__.py
packaging/release/tests/version_helper_test.py
diff --git a/packaging/pep517_backend/_backend.py b/packaging/pep517_backend/_backend.py
index ce97cfab..5086645d 100644
--- a/packaging/pep517_backend/_backend.py
+++ b/packaging/pep517_backend/_backend.py
@@ -77,9 +77,7 @@ def _generate_rst_in_templates() -> t.Iterable[Path]:
"""Create ``*.1.rst.in`` files out of CLI Python modules."""
generate_man_cmd = (
sys.executable,
- 'hacking/build-ansible.py',
- 'generate-man',
- '--template-file=docs/templates/man.j2',
+ Path(__file__).parent / '_generate_man.py',
'--output-dir=docs/man/man1/',
'--output-format=man',
*Path('lib/ansible/cli/').glob('*.py'),
@@ -163,8 +161,7 @@ def get_requires_for_build_sdist(
manpage_build_deps = [
'docutils', # provides `rst2man`
- 'jinja2', # used in `hacking/build-ansible.py generate-man`
- 'straight.plugin', # used in `hacking/build-ansible.py` for subcommand
+ 'jinja2', # used to generate man pages
'pyyaml', # needed for importing in-tree `ansible-core` from `lib/`
] if build_manpages_requested else []
diff --git a/packaging/pep517_backend/_generate_man.py b/packaging/pep517_backend/_generate_man.py
new file mode 100644
index 00000000..d858d4dd
--- /dev/null
+++ b/packaging/pep517_backend/_generate_man.py
@@ -0,0 +1,310 @@
+# coding: utf-8
+# Copyright: (c) 2019, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""Generate cli documentation from cli docstrings."""
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+import argparse
+import os.path
+import pathlib
+import sys
+
+from jinja2 import Environment, FileSystemLoader
+
+DEFAULT_TEMPLATE_FILE = pathlib.Path(__file__).parent / '_templates/man.j2'
+
+
+# from https://www.python.org/dev/peps/pep-0257/
+def trim_docstring(docstring):
+ if not docstring:
+ return ''
+ # Convert tabs to spaces (following the normal Python rules)
+ # and split into a list of lines:
+ lines = docstring.expandtabs().splitlines()
+ # Determine minimum indentation (first line doesn't count):
+ indent = sys.maxsize
+ for line in lines[1:]:
+ stripped = line.lstrip()
+ if stripped:
+ indent = min(indent, len(line) - len(stripped))
+ # Remove indentation (first line is special):
+ trimmed = [lines[0].strip()]
+ if indent < sys.maxsize:
+ for line in lines[1:]:
+ trimmed.append(line[indent:].rstrip())
+ # Strip off trailing and leading blank lines:
+ while trimmed and not trimmed[-1]:
+ trimmed.pop()
+ while trimmed and not trimmed[0]:
+ trimmed.pop(0)
+ # Return a single string:
+ return '\n'.join(trimmed)
+
+
+def get_options(optlist):
+ ''' get actual options '''
+
+ opts = []
+ for opt in optlist:
+ res = {
+ 'desc': opt.help,
+ 'options': opt.option_strings
+ }
+ if isinstance(opt, argparse._StoreAction):
+ res['arg'] = opt.dest.upper()
+ elif not res['options']:
+ continue
+ opts.append(res)
+
+ return opts
+
+
+def dedupe_groups(parser):
+ action_groups = []
+ for action_group in parser._action_groups:
+ found = False
+ for a in action_groups:
+ if a._actions == action_group._actions:
+ found = True
+ break
+ if not found:
+ action_groups.append(action_group)
+ return action_groups
+
+
+def get_option_groups(option_parser):
+ groups = []
+ for action_group in dedupe_groups(option_parser)[1:]:
+ group_info = {}
+ group_info['desc'] = action_group.description
+ group_info['options'] = action_group._actions
+ group_info['group_obj'] = action_group
+ groups.append(group_info)
+ return groups
+
+
+def opt_doc_list(parser):
+ ''' iterate over options lists '''
+
+ results = []
+ for option_group in dedupe_groups(parser)[1:]:
+ results.extend(get_options(option_group._actions))
+
+ results.extend(get_options(parser._actions))
+
+ return results
+
+
+# def opts_docs(cli, name):
+def opts_docs(cli_class_name, cli_module_name):
+ ''' generate doc structure from options '''
+
+ cli_name = 'ansible-%s' % cli_module_name
+ if cli_module_name == 'adhoc':
+ cli_name = 'ansible'
+
+ # WIth no action/subcommand
+ # shared opts set
+ # instantiate each cli and ask its options
+ cli_klass = getattr(__import__("ansible.cli.%s" % cli_module_name,
+ fromlist=[cli_class_name]), cli_class_name)
+ cli = cli_klass([cli_name])
+
+ # parse the common options
+ try:
+ cli.init_parser()
+ except Exception:
+ pass
+
+ # base/common cli info
+ docs = {
+ 'cli': cli_module_name,
+ 'cli_name': cli_name,
+ 'usage': cli.parser.format_usage(),
+ 'short_desc': cli.parser.description,
+ 'long_desc': trim_docstring(cli.__doc__),
+ 'actions': {},
+ 'content_depth': 2,
+ }
+ option_info = {'option_names': [],
+ 'options': [],
+ 'groups': []}
+
+ for extras in ('ARGUMENTS'):
+ if hasattr(cli, extras):
+ docs[extras.lower()] = getattr(cli, extras)
+
+ common_opts = opt_doc_list(cli.parser)
+ groups_info = get_option_groups(cli.parser)
+ shared_opt_names = []
+ for opt in common_opts:
+ shared_opt_names.extend(opt.get('options', []))
+
+ option_info['options'] = common_opts
+ option_info['option_names'] = shared_opt_names
+
+ option_info['groups'].extend(groups_info)
+
+ docs.update(option_info)
+
+ # now for each action/subcommand
+ # force populate parser with per action options
+
+ def get_actions(parser, docs):
+ # use class attrs not the attrs on a instance (not that it matters here...)
+ try:
+ subparser = parser._subparsers._group_actions[0].choices
+ except AttributeError:
+ subparser = {}
+
+ depth = 0
+
+ for action, parser in subparser.items():
+ action_info = {'option_names': [],
+ 'options': [],
+ 'actions': {}}
+ # docs['actions'][action] = {}
+ # docs['actions'][action]['name'] = action
+ action_info['name'] = action
+ action_info['desc'] = trim_docstring(getattr(cli, 'execute_%s' % action).__doc__)
+
+ # docs['actions'][action]['desc'] = getattr(cli, 'execute_%s' % action).__doc__.strip()
+ action_doc_list = opt_doc_list(parser)
+
+ uncommon_options = []
+ for action_doc in action_doc_list:
+ # uncommon_options = []
+
+ option_aliases = action_doc.get('options', [])
+ for option_alias in option_aliases:
+
+ if option_alias in shared_opt_names:
+ continue
+
+ # TODO: use set
+ if option_alias not in action_info['option_names']:
+ action_info['option_names'].append(option_alias)
+
+ if action_doc in action_info['options']:
+ continue
+
+ uncommon_options.append(action_doc)
+
+ action_info['options'] = uncommon_options
+
+ depth = 1 + get_actions(parser, action_info)
+
+ docs['actions'][action] = action_info
+
+ return depth
+
+ action_depth = get_actions(cli.parser, docs)
+ docs['content_depth'] = action_depth + 1
+
+ docs['options'] = opt_doc_list(cli.parser)
+ return docs
+
+
+class GenerateMan:
+ name = 'generate-man'
+
+ @classmethod
+ def init_parser(cls, parser: argparse.ArgumentParser):
+ parser.add_argument("-t", "--template-file", action="store", dest="template_file",
+ default=DEFAULT_TEMPLATE_FILE, help="path to jinja2 template")
+ parser.add_argument("-o", "--output-dir", action="store", dest="output_dir",
+ default='/tmp/', help="Output directory for rst files")
+ parser.add_argument("-f", "--output-format", action="store", dest="output_format",
+ default='man',
+ help="Output format for docs (the default 'man' or 'rst')")
+ parser.add_argument('cli_modules', help='CLI module name(s)', metavar='MODULE_NAME', nargs='*')
+
+ @staticmethod
+ def main(args):
+ template_file = args.template_file
+ template_path = os.path.expanduser(template_file)
+ template_dir = os.path.abspath(os.path.dirname(template_path))
+ template_basename = os.path.basename(template_file)
+
+ output_dir = os.path.abspath(args.output_dir)
+ output_format = args.output_format
+
+ cli_modules = args.cli_modules
+
+ # various cli parsing things checks sys.argv if the 'args' that are passed in are []
+ # so just remove any args so the cli modules dont try to parse them resulting in warnings
+ sys.argv = [sys.argv[0]]
+
+ allvars = {}
+ output = {}
+ cli_list = []
+ cli_bin_name_list = []
+
+ # for binary in os.listdir('../../lib/ansible/cli'):
+ for cli_module_name in cli_modules:
+ binary = os.path.basename(os.path.expanduser(cli_module_name))
+
+ if not binary.endswith('.py'):
+ continue
+ elif binary == '__init__.py':
+ continue
+
+ cli_name = os.path.splitext(binary)[0]
+
+ if cli_name == 'adhoc':
+ cli_class_name = 'AdHocCLI'
+ # myclass = 'AdHocCLI'
+ output[cli_name] = 'ansible.1.rst.in'
+ cli_bin_name = 'ansible'
+ else:
+ # myclass = "%sCLI" % libname.capitalize()
+ cli_class_name = "%sCLI" % cli_name.capitalize()
+ output[cli_name] = 'ansible-%s.1.rst.in' % cli_name
+ cli_bin_name = 'ansible-%s' % cli_name
+
+ # FIXME:
+ allvars[cli_name] = opts_docs(cli_class_name, cli_name)
+ cli_bin_name_list.append(cli_bin_name)
+
+ cli_list = allvars.keys()
+
+ doc_name_formats = {'man': '%s.1.rst.in',
+ 'rst': '%s.rst'}
+
+ for cli_name in cli_list:
+
+ # template it!
+ env = Environment(loader=FileSystemLoader(template_dir))
+ template = env.get_template(template_basename)
+
+ # add rest to vars
+ tvars = allvars[cli_name]
+ tvars['cli_list'] = cli_list
+ tvars['cli_bin_name_list'] = cli_bin_name_list
+ tvars['cli'] = cli_name
+ if '-i' in tvars['options']:
+ print('uses inventory')
+
+ manpage = template.render(tvars)
+ filename = os.path.join(output_dir, doc_name_formats[output_format] % tvars['cli_name'])
+ pathlib.Path(filename).write_text(manpage)
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(description=__doc__)
+
+ GenerateMan.init_parser(parser)
+
+ args = parser.parse_args()
+
+ sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'lib'))
+
+ GenerateMan.main(args)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/packaging/pep517_backend/_templates/man.j2 b/packaging/pep517_backend/_templates/man.j2
new file mode 100644
index 00000000..8bd3644c
--- /dev/null
+++ b/packaging/pep517_backend/_templates/man.j2
@@ -0,0 +1,128 @@
+{% set name = ('ansible' if cli == 'adhoc' else 'ansible-%s' % cli) -%}
+{{name}}
+{{ '=' * ( name|length|int ) }}
+
+{{ '-' * ( short_desc|default('')|string|length|int ) }}
+{{short_desc|default('')}}
+{{ '-' * ( short_desc|default('')|string|length|int ) }}
+
+:Version: Ansible %VERSION%
+:Manual section: 1
+:Manual group: System administration commands
+
+
+
+SYNOPSIS
+--------
+{{ usage|replace('%prog', name) }}
+
+
+DESCRIPTION
+-----------
+{{ long_desc|default('', True)|wordwrap }}
+
+{% if options %}
+COMMON OPTIONS
+--------------
+{% for option in options|sort(attribute='options') %}
+{% for switch in option['options'] %}**{{switch}}**{% if option['arg'] %} '{{option['arg']}}'{% endif %}{% if not loop.last %}, {% endif %}{% endfor %}
+
+ {{ option['desc'] }}
+{% endfor %}
+{% endif %}
+
+{% if arguments %}
+ARGUMENTS
+---------
+
+{% for arg in arguments %}
+{{ arg }}
+
+{{ (arguments[arg]|default(' '))|wordwrap }}
+
+{% endfor %}
+{% endif %}
+
+{% if actions %}
+ACTIONS
+-------
+{% for action in actions %}
+**{{ action }}**
+ {{ (actions[action]['desc']|default(' ')) |replace('\n', ' ')}}
+
+{% if actions[action]['options'] %}
+{% for option in actions[action]['options']|sort(attribute='options') %}
+{% for switch in option['options'] if switch in actions[action]['option_names'] %} **{{switch}}**{% if option['arg'] %} '{{option['arg']}}'{% endif %}{% if not loop.last %}, {% endif %}{% endfor %}
+
+ {{ (option['desc']) }}
+{% endfor %}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+
+{% if inventory %}
+INVENTORY
+---------
+
+Ansible stores the hosts it can potentially operate on in an inventory.
+This can be an YAML file, ini-like file, a script, directory, list, etc.
+For additional options, see the documentation on https://docs.ansible.com/.
+
+{% endif %}
+ENVIRONMENT
+-----------
+
+The following environment variables may be specified.
+
+{% if inventory %}
+ANSIBLE_INVENTORY -- Override the default ansible inventory sources
+
+{% endif %}
+{% if library %}
+ANSIBLE_LIBRARY -- Override the default ansible module library path
+
+{% endif %}
+ANSIBLE_CONFIG -- Specify override location for the ansible config file
+
+Many more are available for most options in ansible.cfg
+
+For a full list check https://docs.ansible.com/. or use the `ansible-config` command.
+
+FILES
+-----
+
+{% if inventory %}
+/etc/ansible/hosts -- Default inventory file
+
+{% endif %}
+/etc/ansible/ansible.cfg -- Config file, used if present
+
+~/.ansible.cfg -- User config file, overrides the default config if present
+
+./ansible.cfg -- Local config file (in current working directory) assumed to be 'project specific' and overrides the rest if present.
+
+As mentioned above, the ANSIBLE_CONFIG environment variable will override all others.
+
+AUTHOR
+------
+
+Ansible was originally written by Michael DeHaan.
+
+
+COPYRIGHT
+---------
+
+Copyright © 2018 Red Hat, Inc | Ansible.
+Ansible is released under the terms of the GPLv3 license.
+
+
+SEE ALSO
+--------
+
+{% for other in cli_list|sort %}{% if other != cli %}**ansible{% if other != 'adhoc' %}-{{other}}{% endif %}** (1){% if not loop.last %}, {% endif %}{% endif %}{% endfor %}
+
+Extensive documentation is available in the documentation site:
+<https://docs.ansible.com>.
+IRC and mailing list info can be found in file CONTRIBUTING.md,
+available in: <https://github.com/ansible/ansible>
diff --git a/test/integration/targets/canonical-pep517-self-packaging/minimum-build-constraints.txt b/test/integration/targets/canonical-pep517-self-packaging/minimum-build-constraints.txt
index ea5d8084..3ba47aeb 100644
--- a/test/integration/targets/canonical-pep517-self-packaging/minimum-build-constraints.txt
+++ b/test/integration/targets/canonical-pep517-self-packaging/minimum-build-constraints.txt
@@ -13,4 +13,3 @@ docutils == 0.16
Jinja2 == 3.0.0
MarkupSafe == 2.0.0
PyYAML == 5.3
-straight.plugin == 1.4.2
diff --git a/test/integration/targets/canonical-pep517-self-packaging/modernish-build-constraints.txt b/test/integration/targets/canonical-pep517-self-packaging/modernish-build-constraints.txt
index 7f744afd..9b8e9d0a 100644
--- a/test/integration/targets/canonical-pep517-self-packaging/modernish-build-constraints.txt
+++ b/test/integration/targets/canonical-pep517-self-packaging/modernish-build-constraints.txt
@@ -8,4 +8,3 @@ docutils == 0.19
Jinja2 == 3.1.2
MarkupSafe == 2.1.2
PyYAML == 6.0
-straight.plugin == 1.5.0 # WARNING: v1.5.0 doesn't have a Git tag / src
diff --git a/test/integration/targets/uri/tasks/main.yml b/test/integration/targets/uri/tasks/main.yml
index 7fa687b4..9ba09ece 100644
--- a/test/integration/targets/uri/tasks/main.yml
+++ b/test/integration/targets/uri/tasks/main.yml
@@ -687,6 +687,18 @@
that:
- result.json.json[0] == 'JSON Test Pattern pass1'
+- name: Test find JSON as subtype
+ uri:
+ url: "https://{{ httpbin_host }}/response-headers?content-type=application/ld%2Bjson"
+ method: POST
+ return_content: true
+ register: result
+
+- name: Validate JSON as subtype
+ assert:
+ that:
+ - result.json is defined
+
- name: Make request that includes password in JSON keys
uri:
url: "https://{{ httpbin_host}}/get?key-password=value-password"
diff --git a/test/lib/ansible_test/_internal/data.py b/test/lib/ansible_test/_internal/data.py
index 379ee7b0..67f7a06c 100644
--- a/test/lib/ansible_test/_internal/data.py
+++ b/test/lib/ansible_test/_internal/data.py
@@ -10,7 +10,6 @@ from .util import (
ApplicationError,
import_plugins,
is_subdir,
- is_valid_identifier,
ANSIBLE_LIB_ROOT,
ANSIBLE_TEST_ROOT,
ANSIBLE_SOURCE_ROOT,
@@ -219,12 +218,8 @@ class DataContext:
elif 'ansible_collections' not in cwd.split(os.path.sep):
blocks.append('No "ansible_collections" parent directory was found.')
- if self.content.collection:
- if not is_valid_identifier(self.content.collection.namespace):
- blocks.append(f'The namespace "{self.content.collection.namespace}" is an invalid identifier or a reserved keyword.')
-
- if not is_valid_identifier(self.content.collection.name):
- blocks.append(f'The name "{self.content.collection.name}" is an invalid identifier or a reserved keyword.')
+ if isinstance(self.content.unsupported, list):
+ blocks.extend(self.content.unsupported)
message = '\n'.join(blocks)
diff --git a/test/lib/ansible_test/_internal/git.py b/test/lib/ansible_test/_internal/git.py
index 4685f1d2..b6c5c7b4 100644
--- a/test/lib/ansible_test/_internal/git.py
+++ b/test/lib/ansible_test/_internal/git.py
@@ -77,7 +77,7 @@ class Git:
def get_branch_fork_point(self, branch: str) -> str:
"""Return a reference to the point at which the given branch was forked."""
- cmd = ['merge-base', '--fork-point', branch]
+ cmd = ['merge-base', branch, 'HEAD']
return self.run_git(cmd).strip()
def is_valid_ref(self, ref: str) -> bool:
diff --git a/test/lib/ansible_test/_internal/provider/layout/__init__.py b/test/lib/ansible_test/_internal/provider/layout/__init__.py
index 4eca05ce..a0a0609b 100644
--- a/test/lib/ansible_test/_internal/provider/layout/__init__.py
+++ b/test/lib/ansible_test/_internal/provider/layout/__init__.py
@@ -95,7 +95,7 @@ class ContentLayout(Layout):
unit_module_path: str,
unit_module_utils_path: str,
unit_messages: t.Optional[LayoutMessages],
- unsupported: bool = False,
+ unsupported: bool | list[str] = False,
) -> None:
super().__init__(root, paths)
diff --git a/test/lib/ansible_test/_internal/provider/layout/ansible.py b/test/lib/ansible_test/_internal/provider/layout/ansible.py
index d2f8cc81..3ee818a5 100644
--- a/test/lib/ansible_test/_internal/provider/layout/ansible.py
+++ b/test/lib/ansible_test/_internal/provider/layout/ansible.py
@@ -8,6 +8,11 @@ from . import (
LayoutProvider,
)
+from ...util import (
+ ANSIBLE_SOURCE_ROOT,
+ ANSIBLE_TEST_ROOT,
+)
+
class AnsibleLayout(LayoutProvider):
"""Layout provider for Ansible source."""
@@ -26,6 +31,15 @@ class AnsibleLayout(LayoutProvider):
module_utils='lib/ansible/module_utils',
)
+ errors: list[str] = []
+
+ if root != ANSIBLE_SOURCE_ROOT:
+ errors.extend((
+ f'Cannot test "{root}" with ansible-test from "{ANSIBLE_TEST_ROOT}".',
+ '',
+ f'Did you intend to run "{root}/bin/ansible-test" instead?',
+ ))
+
return ContentLayout(
root,
paths,
@@ -43,4 +57,5 @@ class AnsibleLayout(LayoutProvider):
unit_module_path='test/units/modules',
unit_module_utils_path='test/units/module_utils',
unit_messages=None,
+ unsupported=errors,
)
diff --git a/test/lib/ansible_test/_internal/provider/layout/collection.py b/test/lib/ansible_test/_internal/provider/layout/collection.py
index d747f31f..a9221be6 100644
--- a/test/lib/ansible_test/_internal/provider/layout/collection.py
+++ b/test/lib/ansible_test/_internal/provider/layout/collection.py
@@ -53,6 +53,14 @@ class CollectionLayout(LayoutProvider):
integration_targets_path = self.__check_integration_path(paths, integration_messages)
self.__check_unit_path(paths, unit_messages)
+ errors: list[str] = []
+
+ if not is_valid_identifier(collection_namespace):
+ errors.append(f'The namespace "{collection_namespace}" is an invalid identifier or a reserved keyword.')
+
+ if not is_valid_identifier(collection_name):
+ errors.append(f'The name "{collection_name}" is an invalid identifier or a reserved keyword.')
+
return ContentLayout(
root,
paths,
@@ -74,7 +82,7 @@ class CollectionLayout(LayoutProvider):
unit_module_path='tests/unit/plugins/modules',
unit_module_utils_path='tests/unit/plugins/module_utils',
unit_messages=unit_messages,
- unsupported=not (is_valid_identifier(collection_namespace) and is_valid_identifier(collection_name)),
+ unsupported=errors,
)
@staticmethod