metadata 1.1

* Add network value to support_by field.
* New support_by value, certified
* Deprecate curated in favor of certified
* Add conversion from 1.0 to 1.1 to metadata-tool
* Add supported by Red Hat field to ansible-doc output
This commit is contained in:
Toshio Kuratomi 2017-08-05 11:28:21 -07:00
parent d50d65d448
commit af2073d057
19 changed files with 175 additions and 71 deletions

View file

@ -255,9 +255,6 @@ def process_module(module, options, env, template, outputname, module_map, alias
if doc is None: if doc is None:
sys.exit("*** ERROR: MODULE MISSING DOCUMENTATION: %s, %s ***\n" % (fname, module)) sys.exit("*** ERROR: MODULE MISSING DOCUMENTATION: %s, %s ***\n" % (fname, module))
if metadata is None:
sys.exit("*** ERROR: MODULE MISSING METADATA: %s, %s ***\n" % (fname, module))
if deprecated and 'deprecated' not in doc: if deprecated and 'deprecated' not in doc:
sys.exit("*** ERROR: DEPRECATED MODULE MISSING 'deprecated' DOCUMENTATION: %s, %s ***\n" % (fname, module)) sys.exit("*** ERROR: DEPRECATED MODULE MISSING 'deprecated' DOCUMENTATION: %s, %s ***\n" % (fname, module))

View file

@ -31,7 +31,7 @@ The following checklist items are important guidelines for people who want to c
ANSIBLE_METADATA = {'status': ['preview'], ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community', 'supported_by': 'community',
'metadata_version': '1.0'} 'metadata_version': '1.1'}
The complete module metadata specification is here: `Ansible metadata block <https://docs.ansible.com/ansible/dev_guide/developing_modules_documenting.html#ansible-metadata-block>`_ The complete module metadata specification is here: `Ansible metadata block <https://docs.ansible.com/ansible/dev_guide/developing_modules_documenting.html#ansible-metadata-block>`_

View file

@ -75,7 +75,7 @@ For new modules, the following block can be simply added into your module
.. code-block:: python .. code-block:: python
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'], 'status': ['preview'],
'supported_by': 'community'} 'supported_by': 'community'}
@ -92,7 +92,7 @@ For new modules, the following block can be simply added into your module
ANSIBLE_METADATA doesn't look quite right because of this. Module ANSIBLE_METADATA doesn't look quite right because of this. Module
metadata should be fixed before checking it into the repository. metadata should be fixed before checking it into the repository.
Version 1.0 of the metadata Version 1.1 of the metadata
+++++++++++++++++++++++++++ +++++++++++++++++++++++++++
Structure Structure
@ -101,7 +101,7 @@ Structure
.. code-block:: python .. code-block:: python
ANSIBLE_METADATA = { ANSIBLE_METADATA = {
'metadata_version': '1.0', 'metadata_version': '1.1',
'supported_by': 'community', 'supported_by': 'community',
'status': ['preview', 'deprecated'] 'status': ['preview', 'deprecated']
} }
@ -115,13 +115,17 @@ Fields
of the metadata. Well increment Y if we add fields or legal values of the metadata. Well increment Y if we add fields or legal values
to an existing field. Well increment X if we remove fields or values to an existing field. Well increment X if we remove fields or values
or change the type or meaning of a field. or change the type or meaning of a field.
Current metadata_version is "1.1"
:supported_by: This field records who supports the module. :supported_by: This field records who supports the module.
Default value is ``community``. Values are: Default value is ``community``. Values are:
:core: * core
:curated: * network
:community: * certfied
* community
* curated (Deprecated. Modules in this category should probably be core or
certified instead)
For information on what the support level values entail, please see For information on what the support level values entail, please see
`Modules Support <http://docs.ansible.com/ansible/modules_support.html>`_. `Modules Support <http://docs.ansible.com/ansible/modules_support.html>`_.
@ -142,6 +146,18 @@ Fields
kept so that documentation can be built. The documentation helps kept so that documentation can be built. The documentation helps
users port from the removed module to new modules. users port from the removed module to new modules.
Changes from Version 1.0
++++++++++++++++++++++++
:metadata_version: Version updated from 1.0 to 1.1
:supported_by: All substantive changes were to potential values of the supported_by field
* Added the certified value
* Deprecated the curated value, modules shipped with Ansible will use
certified instead. Third party modules are encouraged not to use this as
it is meaningless within Ansible proper.
* Added the network value
DOCUMENTATION Block DOCUMENTATION Block
------------------- -------------------

View file

@ -56,9 +56,9 @@ working on a whole new file. Here is an example:
#!/usr/bin/python #!/usr/bin/python
ANSIBLE_METADATA = { ANSIBLE_METADATA = {
'metadata_version': '1.0', 'metadata_version': '1.1',
'status': ['preview'], 'status': ['preview'],
'supported_by': 'curated' 'supported_by': 'community'
} }
DOCUMENTATION = ''' DOCUMENTATION = '''

View file

@ -88,9 +88,9 @@ working on a whole new file. Here is an example:
#!/usr/bin/python #!/usr/bin/python
ANSIBLE_METADATA = { ANSIBLE_METADATA = {
'metadata_version': '1.0', 'metadata_version': '1.1',
'status': ['preview'], 'status': ['preview'],
'supported_by': 'curated' 'supported_by': 'community'
} }
DOCUMENTATION = ''' DOCUMENTATION = '''
@ -401,9 +401,9 @@ working on a whole new file. Here is an example:
#!/usr/bin/python #!/usr/bin/python
ANSIBLE_METADATA = { ANSIBLE_METADATA = {
'metadata_version': '1.0', 'metadata_version': '1.1',
'status': ['preview'], 'status': ['preview'],
'supported_by': 'curated' 'supported_by': 'community'
} }
DOCUMENTATION = ''' DOCUMENTATION = '''
@ -714,9 +714,9 @@ working on a whole new file. Here is an example:
#!/usr/bin/python #!/usr/bin/python
ANSIBLE_METADATA = { ANSIBLE_METADATA = {
'metadata_version': '1.0', 'metadata_version': '1.1',
'status': ['preview'], 'status': ['preview'],
'supported_by': 'curated' 'supported_by': 'community'
} }
DOCUMENTATION = ''' DOCUMENTATION = '''
@ -1027,9 +1027,9 @@ working on a whole new file. Here is an example:
#!/usr/bin/python #!/usr/bin/python
ANSIBLE_METADATA = { ANSIBLE_METADATA = {
'metadata_version': '1.0', 'metadata_version': '1.1',
'status': ['preview'], 'status': ['preview'],
'supported_by': 'curated' 'supported_by': 'community'
} }
DOCUMENTATION = ''' DOCUMENTATION = '''
@ -1340,9 +1340,9 @@ working on a whole new file. Here is an example:
#!/usr/bin/python #!/usr/bin/python
ANSIBLE_METADATA = { ANSIBLE_METADATA = {
'metadata_version': '1.0', 'metadata_version': '1.1',
'status': ['preview'], 'status': ['preview'],
'supported_by': 'curated' 'supported_by': 'community'
} }
DOCUMENTATION = ''' DOCUMENTATION = '''
@ -1569,4 +1569,4 @@ Credit
====== ======
A *huge* thank you to the Ansible team at Red Hat for providing not only A *huge* thank you to the Ansible team at Red Hat for providing not only
a great product but also the willingness to help out contributors! a great product but also the willingness to help out contributors!

View file

@ -18,15 +18,21 @@ The modules are hosted on GitHub in a subdirectory of the `ansible <https://gith
Core Core
```` ````
These are modules that the core ansible team maintains and will always ship with ansible itself. These are modules that the Ansible Core Team maintains and will always ship with Ansible itself.
They will also receive slightly higher priority for all requests. Non-core modules are still fully usable. They will also receive slightly higher priority for all requests. Non-core modules are still fully usable.
Curated Network
``````` ```````
Some examples of Curated modules are submitted by other companies or maintained by the community. Maintainers of these types of modules must watch for any issues reported or pull requests raised against the module. These modules are supported by the Ansible Network Team in a relationship
similar to how the Ansible Core Team maintains the Core modules.
Core Committers will review all modules becoming Curated. Core Committers will review proposed changes to existing Curated modules once the community maintainers of the module have approved the changes. Core committers will also ensure that any issues that arise due to Ansible engine changes will be remediated. Certified
`````````
Some examples of Certified modules are those submitted by other companies. Maintainers of these types of modules must watch for any issues reported or pull requests raised against the module.
Core Committers will review all modules becoming Certified. Core Committers will review proposed changes to existing Certified modules once the community maintainers of the module have approved the changes. Core committers will also ensure that any issues that arise due to Ansible engine changes will be remediated.
Also, it is strongly recommended (but not presently required) for these types of modules to have unit tests. Also, it is strongly recommended (but not presently required) for these types of modules to have unit tests.
These modules are currently shipped with Ansible, but might be shipped separately in the future. These modules are currently shipped with Ansible, but might be shipped separately in the future.

View file

@ -207,7 +207,7 @@ Notes
{% endif %} {% endif %}
{% if not deprecated %} {% if not deprecated %}
{% set support = { 'core': 'This module is maintained by those with core commit privileges', 'curated': 'This module is supported mainly by the community and is curated by core committers.', 'community': 'This module is community maintained without core committer oversight.'} %} {% set support = { 'core': 'The Ansible Core Team', 'network': 'The Ansible Network Team', 'certified': 'an Ansible Partner', 'community': 'The Ansible Community', 'curated': 'A Third Party'} %}
{% set module_states = { 'preview': 'it is not guaranteed to have a backwards compatible interface', 'stableinterface': 'the maintainers for this module guarantee that no backward incompatible interface changes will be made'} %} {% set module_states = { 'preview': 'it is not guaranteed to have a backwards compatible interface', 'stableinterface': 'the maintainers for this module guarantee that no backward incompatible interface changes will be made'} %}
{% if metadata %} {% if metadata %}
@ -223,10 +223,10 @@ This module is flagged as **@{cur_state}@** which means that @{module_states[cur
{% if metadata.supported_by %} {% if metadata.supported_by %}
Support Support Level
~~~~~~~ ~~~~~~~~~~~~~
@{ support[metadata.supported_by] }@ This module is maintained by @{ support[metadata.supported_by] }@
For more information on what this means please read :doc:`modules_support` For more information on what this means please read :doc:`modules_support`

View file

@ -28,17 +28,14 @@ from collections import defaultdict
from distutils.version import StrictVersion from distutils.version import StrictVersion
from pprint import pformat, pprint from pprint import pformat, pprint
from ansible.parsing.metadata import ParseError, extract_metadata from ansible.parsing.metadata import DEFAULT_METADATA, ParseError, extract_metadata
from ansible.plugins import module_loader from ansible.plugins.loader import module_loader
# There's a few files that are not new-style modules. Have to blacklist them # There's a few files that are not new-style modules. Have to blacklist them
NONMODULE_PY_FILES = frozenset(('async_wrapper.py',)) NONMODULE_PY_FILES = frozenset(('async_wrapper.py',))
NONMODULE_MODULE_NAMES = frozenset(os.path.splitext(p)[0] for p in NONMODULE_PY_FILES) NONMODULE_MODULE_NAMES = frozenset(os.path.splitext(p)[0] for p in NONMODULE_PY_FILES)
# Default metadata
DEFAULT_METADATA = {'metadata_version': '1.0', 'status': ['preview'], 'supported_by': 'community'}
class MissingModuleError(Exception): class MissingModuleError(Exception):
"""Thrown when unable to find a plugin""" """Thrown when unable to find a plugin"""
@ -123,7 +120,7 @@ def insert_metadata(module_data, new_metadata, insertion_line, targets=('ANSIBLE
new_lines.append('{}{}'.format(' ' * (len(assignments) - 1 + len(' = {')), line)) new_lines.append('{}{}'.format(' ' * (len(assignments) - 1 + len(' = {')), line))
old_lines = module_data.split('\n') old_lines = module_data.split('\n')
lines = old_lines[:insertion_line] + new_lines + [''] + old_lines[insertion_line:] lines = old_lines[:insertion_line] + new_lines + old_lines[insertion_line:]
return '\n'.join(lines) return '\n'.join(lines)
@ -174,13 +171,13 @@ def parse_assigned_metadata(csvfile):
Fields: Fields:
:0: Module name :0: Module name
:1: supported_by string. One of the valid support fields :1: supported_by string. One of the valid support fields
core, community, curated core, community, certified, network
:2: stableinterface :2: stableinterface
:3: preview :3: preview
:4: deprecated :4: deprecated
:5: removed :5: removed
https://github.com/ansible/proposals/issues/30 http://docs.ansible.com/ansible/latest/dev_guide/developing_modules_documenting.html#ansible-metadata-block
""" """
with open(csvfile, 'rb') as f: with open(csvfile, 'rb') as f:
for record in csv.reader(f): for record in csv.reader(f):
@ -197,7 +194,7 @@ def parse_assigned_metadata(csvfile):
if not status or record[3]: if not status or record[3]:
status.append('preview') status.append('preview')
yield (module, {'metadata_version': '1.0', 'supported_by': supported_by, 'status': status}) yield (module, {'metadata_version': '1.1', 'supported_by': supported_by, 'status': status})
def write_metadata(filename, new_metadata, version=None, overwrite=False): def write_metadata(filename, new_metadata, version=None, overwrite=False):
@ -330,6 +327,31 @@ def convert_metadata_pre_1_0_to_1_0(metadata):
return new_metadata return new_metadata
def convert_metadata_1_0_to_1_1(metadata):
"""
Convert 1.0 to 1.1 metadata format
:arg metadata: The old metadata
:returns: The new metadata
Changes from 1.0 to 1.1:
* ``supported_by`` field value ``curated`` has been removed
* ``supported_by`` field value ``certified`` has been added
* ``supported_by`` field value ``network`` has been added
"""
new_metadata = {'metadata_version': '1.1',
'supported_by': metadata['supported_by'],
'status': metadata['status']
}
if new_metadata['supported_by'] == 'unmaintained':
new_metadata['supported_by'] = 'community'
elif new_metadata['supported_by'] == 'curated':
new_metadata['supported_by'] = 'certified'
return new_metadata
# Subcommands # Subcommands
@ -338,7 +360,7 @@ def add_from_csv(csv_file, version=None, overwrite=False):
""" """
# Add metadata for everything from the CSV file # Add metadata for everything from the CSV file
diagnostic_messages = [] diagnostic_messages = []
for module_name, new_metadata in parse_assigned_metadata_initial(csv_file): for module_name, new_metadata in parse_assigned_metadata(csv_file):
filename = module_loader.find_plugin(module_name, mod_type='.py') filename = module_loader.find_plugin(module_name, mod_type='.py')
if filename is None: if filename is None:
diagnostic_messages.append('Unable to find the module file for {}'.format(module_name)) diagnostic_messages.append('Unable to find the module file for {}'.format(module_name))
@ -424,7 +446,10 @@ def upgrade_metadata(version=None):
metadata = convert_metadata_pre_1_0_to_1_0(metadata) metadata = convert_metadata_pre_1_0_to_1_0(metadata)
if metadata['metadata_version'] == '1.0' and StrictVersion('1.0') < requested_version: if metadata['metadata_version'] == '1.0' and StrictVersion('1.0') < requested_version:
# 1.0 version => XXX. We don't yet have anything beyond 1.0 metadata = convert_metadata_1_0_to_1_1(metadata)
if metadata['metadata_version'] == '1.1' and StrictVersion('1.1') < requested_version:
# 1.1 version => XXX. We don't yet have anything beyond 1.1
# so there's nothing here # so there's nothing here
pass pass
@ -469,8 +494,10 @@ def report(version=None):
print('== Supported by core ==') print('== Supported by core ==')
pprint(sorted(support['core'])) pprint(sorted(support['core']))
print('== Supported by value curated ==') print('== Supported by value certified ==')
pprint(sorted(support['curated'])) pprint(sorted(support['certified']))
print('== Supported by value network ==')
pprint(sorted(support['network']))
print('== Supported by community ==') print('== Supported by community ==')
pprint(sorted(support['community'])) pprint(sorted(support['community']))
print('') print('')
@ -487,8 +514,8 @@ def report(version=None):
print('== Summary ==') print('== Summary ==')
print('No Metadata: {0} Has Metadata: {1}'.format(len(no_metadata), len(has_metadata))) print('No Metadata: {0} Has Metadata: {1}'.format(len(no_metadata), len(has_metadata)))
print('Supported by core: {0} Supported by community: {1} Supported by value curated: {2}'.format(len(support['core']), print('Support level: core: {0} community: {1} certified: {2} network: {3}'.format(len(support['core']),
len(support['community']), len(support['curated']))) len(support['community']), len(support['certified']), len(support['network'])))
print('Status StableInterface: {0} Status Preview: {1} Status Deprecated: {2} Status Removed: {3}'.format(len(status['stableinterface']), print('Status StableInterface: {0} Status Preview: {1} Status Deprecated: {2} Status Removed: {3}'.format(len(status['stableinterface']),
len(status['preview']), len(status['deprecated']), len(status['removed']))) len(status['preview']), len(status['deprecated']), len(status['removed'])))

View file

@ -361,6 +361,36 @@ class DocCLI(CLI):
text.append(self._dump_yaml({k: opt[k]}, opt_indent)) text.append(self._dump_yaml({k: opt[k]}, opt_indent))
text.append('') text.append('')
@staticmethod
def get_support_block(doc):
# Note: 'curated' is deprecated and not used in any of the modules we ship
support_level_msg = {'core': 'The Ansible Core Team',
'network': 'The Ansible Network Team',
'certified': 'an Ansible Partner',
'community': 'The Ansible Community',
'curated': 'A Third Party',
}
if doc['metadata'].get('metadata_version') in ('1.0', '1.1'):
return [" * This module is maintained by %s" % support_level_msg[doc['metadata']['supported_by']]]
return []
@staticmethod
def get_metadata_block(doc):
text = []
if doc['metadata'].get('metadata_version') in ('1.0', '1.1'):
text.append("METADATA:")
text.append('\tSUPPORT LEVEL: %s' % doc['metadata']['supported_by'])
for k in (m for m in doc['metadata'] if m not in ('version', 'metadata_version', 'supported_by')):
if isinstance(k, list):
text.append("\t%s: %s" % (k.capitalize(), ", ".join(doc['metadata'][k])))
else:
text.append("\t%s: %s" % (k.capitalize(), doc['metadata'][k]))
return text
return []
def get_man_text(self, doc): def get_man_text(self, doc):
IGNORE = frozenset(['module', 'docuri', 'version_added', 'short_description', 'now_date']) IGNORE = frozenset(['module', 'docuri', 'version_added', 'short_description', 'now_date'])
@ -381,6 +411,10 @@ class DocCLI(CLI):
if 'deprecated' in doc and doc['deprecated'] is not None and len(doc['deprecated']) > 0: if 'deprecated' in doc and doc['deprecated'] is not None and len(doc['deprecated']) > 0:
text.append("DEPRECATED: \n%s\n" % doc.pop('deprecated')) text.append("DEPRECATED: \n%s\n" % doc.pop('deprecated'))
support_block = self.get_support_block(doc)
if support_block:
text.extend(support_block)
if doc.pop('action', False): if doc.pop('action', False):
text.append(" * note: %s\n" % "This module has a corresponding action plugin.") text.append(" * note: %s\n" % "This module has a corresponding action plugin.")
@ -435,4 +469,9 @@ class DocCLI(CLI):
text.append(self._dump_yaml({k.upper(): doc[k]}, opt_indent)) text.append(self._dump_yaml({k.upper(): doc[k]}, opt_indent))
text.append('') text.append('')
metadata_block = self.get_metadata_block(doc)
if metadata_block:
text.extend(metadata_block)
text.append('')
return "\n".join(text) return "\n".join(text)

View file

@ -27,6 +27,11 @@ import yaml
from ansible.module_utils._text import to_text from ansible.module_utils._text import to_text
# There are currently defaults for all metadata fields so we can add it
# automatically if a file doesn't specify it
DEFAULT_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
class ParseError(Exception): class ParseError(Exception):
"""Thrown when parsing a file fails""" """Thrown when parsing a file fails"""
pass pass

View file

@ -20,7 +20,7 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core'} 'supported_by': 'core'}

View file

@ -20,7 +20,7 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core'} 'supported_by': 'core'}

View file

@ -20,7 +20,7 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core'} 'supported_by': 'core'}

View file

@ -20,7 +20,7 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core'} 'supported_by': 'core'}

View file

@ -20,7 +20,7 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core'} 'supported_by': 'core'}

View file

@ -20,7 +20,7 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core'} 'supported_by': 'core'}

View file

@ -41,7 +41,7 @@ from ansible.utils.plugin_docs import BLACKLIST, get_docstring
from module_args import get_argument_spec from module_args import get_argument_spec
from schema import doc_schema, metadata_schema, return_schema from schema import doc_schema, metadata_1_1_schema, return_schema
from utils import CaptureStd, parse_yaml from utils import CaptureStd, parse_yaml
from voluptuous.humanize import humanize_error from voluptuous.humanize import humanize_error
@ -892,7 +892,7 @@ class ModuleValidator(Validator):
) )
if metadata: if metadata:
self._validate_docs_schema(metadata, metadata_schema(deprecated), self._validate_docs_schema(metadata, metadata_1_1_schema(deprecated),
'ANSIBLE_METADATA', 316) 'ANSIBLE_METADATA', 316)
return doc_info return doc_info

View file

@ -104,7 +104,7 @@ def doc_schema(module_name):
) )
def metadata_schema(deprecated): def metadata_1_0_schema(deprecated):
valid_status = Any('stableinterface', 'preview', 'deprecated', 'removed') valid_status = Any('stableinterface', 'preview', 'deprecated', 'removed')
if deprecated: if deprecated:
valid_status = Any('deprecated') valid_status = Any('deprecated')
@ -118,6 +118,20 @@ def metadata_schema(deprecated):
) )
def metadata_1_1_schema(deprecated):
valid_status = Any('stableinterface', 'preview', 'deprecated', 'removed')
if deprecated:
valid_status = Any('deprecated')
return Schema(
{
Required('status'): [valid_status],
Required('metadata_version'): '1.1',
Required('supported_by'): Any('core', 'community', 'certified', 'network')
}
)
# Things to add soon # Things to add soon
#################### ####################
# 1) Recursively validate `type: complex` fields # 1) Recursively validate `type: complex` fields

View file

@ -41,14 +41,14 @@ from foo import bar
""" """
STANDARD_METADATA = b""" STANDARD_METADATA = b"""
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core'} 'supported_by': 'core'}
""" """
TEXT_STD_METADATA = b""" TEXT_STD_METADATA = b"""
ANSIBLE_METADATA = u''' ANSIBLE_METADATA = u'''
metadata_version: '1.0' metadata_version: '1.1'
status: status:
- 'stableinterface' - 'stableinterface'
supported_by: 'core' supported_by: 'core'
@ -57,7 +57,7 @@ supported_by: 'core'
BYTES_STD_METADATA = b""" BYTES_STD_METADATA = b"""
ANSIBLE_METADATA = b''' ANSIBLE_METADATA = b'''
metadata_version: '1.0' metadata_version: '1.1'
status: status:
- 'stableinterface' - 'stableinterface'
supported_by: 'core' supported_by: 'core'
@ -65,45 +65,45 @@ supported_by: 'core'
""" """
TRAILING_COMMENT_METADATA = b""" TRAILING_COMMENT_METADATA = b"""
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core'} # { Testing } 'supported_by': 'core'} # { Testing }
""" """
MULTIPLE_STATEMENTS_METADATA = b""" MULTIPLE_STATEMENTS_METADATA = b"""
DOCUMENTATION = "" ; ANSIBLE_METADATA = {'metadata_version': '1.0', DOCUMENTATION = "" ; ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core'} ; RETURNS = "" 'supported_by': 'core'} ; RETURNS = ""
""" """
EMBEDDED_COMMENT_METADATA = b""" EMBEDDED_COMMENT_METADATA = b"""
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
# { Testing } # { Testing }
'supported_by': 'core'} 'supported_by': 'core'}
""" """
HASH_SYMBOL_METADATA = b""" HASH_SYMBOL_METADATA = b"""
ANSIBLE_METADATA = {'metadata_version': '1.0 # 4', ANSIBLE_METADATA = {'metadata_version': '1.1 # 4',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core # Testing '} 'supported_by': 'core # Testing '}
""" """
HASH_SYMBOL_METADATA = b""" HASH_SYMBOL_METADATA = b"""
ANSIBLE_METADATA = {'metadata_version': '1.0 # 4', ANSIBLE_METADATA = {'metadata_version': '1.1 # 4',
'status': ['stableinterface'], 'status': ['stableinterface'],
'supported_by': 'core # Testing '} 'supported_by': 'core # Testing '}
""" """
HASH_COMBO_METADATA = b""" HASH_COMBO_METADATA = b"""
ANSIBLE_METADATA = {'metadata_version': '1.0 # 4', ANSIBLE_METADATA = {'metadata_version': '1.1 # 4',
'status': ['stableinterface'], 'status': ['stableinterface'],
# { Testing } # { Testing }
'supported_by': 'core'} # { Testing } 'supported_by': 'core'} # { Testing }
""" """
METADATA = {'metadata_version': '1.0', 'status': ['stableinterface'], 'supported_by': 'core'} METADATA = {'metadata_version': '1.1', 'status': ['stableinterface'], 'supported_by': 'core'}
HASH_SYMBOL_METADATA = {'metadata_version': '1.0 # 4', 'status': ['stableinterface'], 'supported_by': 'core'} HASH_SYMBOL_METADATA = {'metadata_version': '1.1 # 4', 'status': ['stableinterface'], 'supported_by': 'core'}
METADATA_EXAMPLES = ( METADATA_EXAMPLES = (
# Standard import # Standard import
@ -225,15 +225,15 @@ def test_module_data_param_given_with_offset():
def test_invalid_dict_metadata(): def test_invalid_dict_metadata():
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
assert md.extract_metadata(module_data=LICENSE + FUTURE_IMPORTS + b'ANSIBLE_METADATA={"metadata_version": "1.0",\n' + REGULAR_IMPORTS) assert md.extract_metadata(module_data=LICENSE + FUTURE_IMPORTS + b'ANSIBLE_METADATA={"metadata_version": "1.1",\n' + REGULAR_IMPORTS)
with pytest.raises(md.ParseError, message='Unable to find the end of dictionary'): with pytest.raises(md.ParseError, message='Unable to find the end of dictionary'):
assert md.extract_metadata(module_ast=ast.parse(LICENSE + FUTURE_IMPORTS + b'ANSIBLE_METADATA={"metadata_version": "1.0"}\n' + REGULAR_IMPORTS), assert md.extract_metadata(module_ast=ast.parse(LICENSE + FUTURE_IMPORTS + b'ANSIBLE_METADATA={"metadata_version": "1.1"}\n' + REGULAR_IMPORTS),
module_data=LICENSE + FUTURE_IMPORTS + b'ANSIBLE_METADATA={"metadata_version": "1.0",\n' + REGULAR_IMPORTS, module_data=LICENSE + FUTURE_IMPORTS + b'ANSIBLE_METADATA={"metadata_version": "1.1",\n' + REGULAR_IMPORTS,
offsets=True) offsets=True)
def test_multiple_statements_limitation(): def test_multiple_statements_limitation():
with pytest.raises(md.ParseError, message='Multiple statements per line confuses the module metadata parser.'): with pytest.raises(md.ParseError, message='Multiple statements per line confuses the module metadata parser.'):
assert md.extract_metadata(module_data=LICENSE + FUTURE_IMPORTS + b'ANSIBLE_METADATA={"metadata_version": "1.0"}; a=b\n' + REGULAR_IMPORTS, assert md.extract_metadata(module_data=LICENSE + FUTURE_IMPORTS + b'ANSIBLE_METADATA={"metadata_version": "1.1"}; a=b\n' + REGULAR_IMPORTS,
offsets=True) offsets=True)