diff --git a/changelogs/fragments/ps-import-sanity.yml b/changelogs/fragments/ps-import-sanity.yml new file mode 100644 index 00000000000..6d77dcbe876 --- /dev/null +++ b/changelogs/fragments/ps-import-sanity.yml @@ -0,0 +1,3 @@ +bugfixes: + - ansible-test - Fix support for detecting PowerShell modules importing module utils with the newer ``#AnsibleRequires`` format. + - ansible-test - Fix support for PowerShell module_util imports with the ``-Optional`` flag. diff --git a/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_ansible_requires.ps1 b/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_ansible_requires.ps1 new file mode 100644 index 00000000000..ce2072dd1da --- /dev/null +++ b/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_ansible_requires.ps1 @@ -0,0 +1,6 @@ +#!powershell +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#AnsibleRequires -PowerShell Ansible.ModuleUtils.Legacy + +'{"changed": false, "msg": "Hello, World!"}' diff --git a/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_ansible_requires.yml b/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_ansible_requires.yml new file mode 100644 index 00000000000..aa0c0450eca --- /dev/null +++ b/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_ansible_requires.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2025 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +DOCUMENTATION: + module: util_ansible_requires + short_description: Short description for util_ansible_requires module + description: + - Description for util_ansible_requires module + options: {} + author: + - Ansible Core Team + +EXAMPLES: | + - name: example for sidecar + ns.col.util_ansible_requires: + +RETURN: {} diff --git a/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_optional.ps1 b/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_optional.ps1 new file mode 100644 index 00000000000..802fefc4f33 --- /dev/null +++ b/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_optional.ps1 @@ -0,0 +1,14 @@ +#!powershell +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#AnsibleRequires -CSharpUtil Ansible.Basic +#AnsibleRequires -PowerShell .foo -Optional + +$module = [Ansible.Basic.AnsibleModule]::Create( + $args, + @{ + options = @{} + } +) + +$module.ExitJson() diff --git a/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_optional.yml b/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_optional.yml new file mode 100644 index 00000000000..1c2fe7ba919 --- /dev/null +++ b/test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_optional.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2025 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +DOCUMENTATION: + module: util_optional + short_description: Short description for util_optional module + description: + - Description for util_optional module + options: {} + author: + - Ansible Core Team + +EXAMPLES: | + - name: example for sidecar + ns.col.util_optional: + +RETURN: {} diff --git a/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py b/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py index 6ddd12c4028..5f02f64c64d 100644 --- a/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +++ b/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py @@ -687,30 +687,57 @@ class ModuleValidator(Validator): # get module list for each # check "shape" of each module name - module_requires = r'(?im)^#\s*requires\s+\-module(?:s?)\s*(Ansible\.ModuleUtils\..+)' - csharp_requires = r'(?im)^#\s*ansiblerequires\s+\-csharputil\s*(Ansible\..+)' + legacy_ps_requires = r'(?im)^#\s*Requires\s+\-Module(?:s?)\s+(Ansible\.ModuleUtils\..+)' + ps_requires = r'''(?imx) + ^\#\s*AnsibleRequires\s+-PowerShell\s+ + ( + # Builtin PowerShell module + (Ansible\.ModuleUtils\.[\w\.]+) + | + # Fully qualified collection PowerShell module + (ansible_collections\.\w+\.\w+\.plugins\.module_utils\.[\w\.]+) + | + # Relative collection PowerShell module + (\.[\w\.]+) + ) + (\s+-Optional)?''' + csharp_requires = r'''(?imx) + ^\#\s*AnsibleRequires\s+-CSharpUtil\s+ + ( + # Builtin C# util + (Ansible\.[\w\.]+) + | + # Fully qualified collection C# util + (ansible_collections\.\w+\.\w+\.plugins\.module_utils\.[\w\.]+) + | + # Relative collection C# util + (\.[\w\.]+) + ) + (\s+-Optional)?''' + found_requires = False - for req_stmt in re.finditer(module_requires, self.text): - found_requires = True - # this will bomb on dictionary format - "don't do that" - module_list = [x.strip() for x in req_stmt.group(1).split(',')] - if len(module_list) > 1: - self.reporter.error( - path=self.object_path, - code='multiple-utils-per-requires', - msg='Ansible.ModuleUtils requirements do not support multiple modules per statement: "%s"' % req_stmt.group(0) - ) - continue + for pattern, required_type in [(legacy_ps_requires, "Requires"), (ps_requires, "AnsibleRequires")]: + for req_stmt in re.finditer(pattern, self.text): + found_requires = True + # this will bomb on dictionary format - "don't do that" + module_list = [x.strip() for x in req_stmt.group(1).split(',')] + if len(module_list) > 1: + self.reporter.error( + path=self.object_path, + code='multiple-utils-per-requires', + msg='Ansible.ModuleUtils requirements do not support multiple modules per statement: "%s"' % req_stmt.group(0) + ) + continue - module_name = module_list[0] + module_name = module_list[0] - if module_name.lower().endswith('.psm1'): - self.reporter.error( - path=self.object_path, - code='invalid-requires-extension', - msg='Module #Requires should not end in .psm1: "%s"' % module_name - ) + if module_name.lower().endswith('.psm1'): + self.reporter.error( + path=self.object_path, + code='invalid-requires-extension', + msg='Module #%s should not end in .psm1: "%s"' % (required_type, module_name) + ) for req_stmt in re.finditer(csharp_requires, self.text): found_requires = True