mirror of https://github.com/ansible/ansible.git
Generate galaxy.yml based on single source of truth (#59170)
* Generate galaxy.yml based on single source of truth * Fix up tests and align file names * Minor Makefile tweak * Remove link in galaxy.yml file and make it a template file * Moved collections docs to dev_guide * change Makefile clean path * Added readme to example meta file * review fixes * Use newer style for doc generation script * Fix mistake in dev_guide index * removed uneeded file, fixed links and added preview banner * Moved banner for sanity testpull/59408/head
parent
28b9f71640
commit
65049620ee
@ -0,0 +1,74 @@
|
||||
.. _collections_galaxy_meta:
|
||||
|
||||
************************************
|
||||
Collection Galaxy Metadata Structure
|
||||
************************************
|
||||
|
||||
.. important::
|
||||
This feature is available in Ansible 2.8 as a *Technology Preview* and therefore is not fully supported. It should only be used for testing and should not be deployed in a production environment.
|
||||
Future Galaxy or Ansible releases may introduce breaking changes.
|
||||
|
||||
A key component of an Ansible collection is the ``galaxy.yml`` file placed in the root directory of a collection. This
|
||||
file contains the metadata of the collection that is used to generate a collection artifact.
|
||||
|
||||
Structure
|
||||
=========
|
||||
|
||||
The ``galaxy.yml`` file must contain the following keys in valid YAML:
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<table border=0 cellpadding=0 class="documentation-table">
|
||||
{# Header of the documentation -#}
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th width="100%">Comments</th>
|
||||
</tr>
|
||||
{% for entry in options %}
|
||||
<tr>
|
||||
{# key name with required or type label #}
|
||||
<td>
|
||||
<b>@{ entry.key }@</b>
|
||||
<div style="font-size: small">
|
||||
<span style="color: purple">@{ entry.type | documented_type }@</span>
|
||||
{% if entry.get('required', False) %} / <span style="color: red">required</span>{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
{# Comments #}
|
||||
<td>
|
||||
{% if entry.description is string %}
|
||||
<div>@{ entry.description | replace('\n', '\n ') | html_ify }@</div>
|
||||
{% else %}
|
||||
{% for desc in entry.description %}
|
||||
<div>@{ desc | replace('\n', '\n ') | html_ify }@</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<br/>
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
namespace: "namespace_name"
|
||||
name: "collection_name"
|
||||
version: "1.0.12"
|
||||
readme: "README.md"
|
||||
authors:
|
||||
- "Author1"
|
||||
- "Author2 (https://author2.example.com)"
|
||||
- "Author3 <author3@example.com>"
|
||||
dependencies:
|
||||
"other_namespace.collection1": ">=1.0.0"
|
||||
"other_namespace.collection2": ">=2.0.0,<3.0.0"
|
||||
"anderson55.my_collection": "*" # note: "*" selects the highest version available
|
||||
license:
|
||||
- "MIT"
|
||||
tags:
|
||||
- demo
|
||||
- collection
|
||||
repository: "https://www.github.com/my_org/my_collection"
|
@ -0,0 +1,68 @@
|
||||
# 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)
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import pathlib
|
||||
|
||||
import yaml
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
from ansible.module_utils._text import to_bytes
|
||||
|
||||
# Pylint doesn't understand Python3 namespace modules.
|
||||
from ..change_detection import update_file_if_different # pylint: disable=relative-beyond-top-level
|
||||
from ..commands import Command # pylint: disable=relative-beyond-top-level
|
||||
from ..jinja2.filters import documented_type, html_ify # pylint: disable=relative-beyond-top-level
|
||||
|
||||
|
||||
DEFAULT_TEMPLATE_FILE = 'collections_galaxy_meta.rst.j2'
|
||||
DEFAULT_TEMPLATE_DIR = pathlib.Path(__file__).parents[4] / 'docs/templates'
|
||||
|
||||
|
||||
class DocumentCollectionMeta(Command):
|
||||
name = 'collection-meta'
|
||||
|
||||
@classmethod
|
||||
def init_parser(cls, add_parser):
|
||||
parser = add_parser(cls.name, description='Generate collection galaxy.yml documentation from shared metadata')
|
||||
parser.add_argument("-t", "--template-file", action="store", dest="template_file",
|
||||
default=DEFAULT_TEMPLATE_FILE,
|
||||
help="Jinja2 template to use for the config")
|
||||
parser.add_argument("-T", "--template-dir", action="store", dest="template_dir",
|
||||
default=DEFAULT_TEMPLATE_DIR,
|
||||
help="directory containing Jinja2 templates")
|
||||
parser.add_argument("-o", "--output-dir", action="store", dest="output_dir", default='/tmp/',
|
||||
help="Output directory for rst files")
|
||||
parser.add_argument("collection_defs", metavar="COLLECTION-OPTION-DEFINITIONS.yml", type=str,
|
||||
help="Source for collection metadata option docs")
|
||||
|
||||
@staticmethod
|
||||
def main(args):
|
||||
output_dir = os.path.abspath(args.output_dir)
|
||||
template_file_full_path = os.path.abspath(os.path.join(args.template_dir, args.template_file))
|
||||
template_file = os.path.basename(template_file_full_path)
|
||||
template_dir = os.path.dirname(template_file_full_path)
|
||||
|
||||
with open(args.collection_defs) as f:
|
||||
options = yaml.safe_load(f)
|
||||
|
||||
env = Environment(loader=FileSystemLoader(template_dir),
|
||||
variable_start_string="@{",
|
||||
variable_end_string="}@",
|
||||
trim_blocks=True)
|
||||
env.filters['documented_type'] = documented_type
|
||||
env.filters['html_ify'] = html_ify
|
||||
|
||||
template = env.get_template(template_file)
|
||||
output_name = os.path.join(output_dir, template_file.replace('.j2', ''))
|
||||
temp_vars = {'options': options}
|
||||
|
||||
data = to_bytes(template.render(temp_vars))
|
||||
update_file_if_different(output_name, data)
|
||||
|
||||
return 0
|
@ -0,0 +1,100 @@
|
||||
# Copyright: (c) 2019, Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
|
||||
try:
|
||||
from html import escape as html_escape
|
||||
except ImportError:
|
||||
# Python-3.2 or later
|
||||
import cgi
|
||||
|
||||
def html_escape(text, quote=True):
|
||||
return cgi.escape(text, quote)
|
||||
|
||||
from jinja2.runtime import Undefined
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.six import string_types
|
||||
|
||||
|
||||
_ITALIC = re.compile(r"I\(([^)]+)\)")
|
||||
_BOLD = re.compile(r"B\(([^)]+)\)")
|
||||
_MODULE = re.compile(r"M\(([^)]+)\)")
|
||||
_URL = re.compile(r"U\(([^)]+)\)")
|
||||
_LINK = re.compile(r"L\(([^)]+),([^)]+)\)")
|
||||
_CONST = re.compile(r"C\(([^)]+)\)")
|
||||
_RULER = re.compile(r"HORIZONTALLINE")
|
||||
|
||||
|
||||
def html_ify(text):
|
||||
''' convert symbols like I(this is in italics) to valid HTML '''
|
||||
|
||||
if not isinstance(text, string_types):
|
||||
text = to_text(text)
|
||||
|
||||
t = html_escape(text)
|
||||
t = _ITALIC.sub(r"<em>\1</em>", t)
|
||||
t = _BOLD.sub(r"<b>\1</b>", t)
|
||||
t = _MODULE.sub(r"<span class='module'>\1</span>", t)
|
||||
t = _URL.sub(r"<a href='\1'>\1</a>", t)
|
||||
t = _LINK.sub(r"<a href='\2'>\1</a>", t)
|
||||
t = _CONST.sub(r"<code>\1</code>", t)
|
||||
t = _RULER.sub(r"<hr/>", t)
|
||||
|
||||
return t.strip()
|
||||
|
||||
|
||||
def documented_type(text):
|
||||
''' Convert any python type to a type for documentation '''
|
||||
|
||||
if isinstance(text, Undefined):
|
||||
return '-'
|
||||
if text == 'str':
|
||||
return 'string'
|
||||
if text == 'bool':
|
||||
return 'boolean'
|
||||
if text == 'int':
|
||||
return 'integer'
|
||||
if text == 'dict':
|
||||
return 'dictionary'
|
||||
return text
|
||||
|
||||
|
||||
# The max filter was added in Jinja2-2.10. Until we can require that version, use this
|
||||
def do_max(seq):
|
||||
return max(seq)
|
||||
|
||||
|
||||
def rst_ify(text):
|
||||
''' convert symbols like I(this is in italics) to valid restructured text '''
|
||||
|
||||
try:
|
||||
t = _ITALIC.sub(r"*\1*", text)
|
||||
t = _BOLD.sub(r"**\1**", t)
|
||||
t = _MODULE.sub(r":ref:`\1 <\1_module>`", t)
|
||||
t = _LINK.sub(r"`\1 <\2>`_", t)
|
||||
t = _URL.sub(r"\1", t)
|
||||
t = _CONST.sub(r"``\1``", t)
|
||||
t = _RULER.sub(r"------------", t)
|
||||
except Exception as e:
|
||||
raise AnsibleError("Could not process (%s) : %s" % (text, e))
|
||||
|
||||
return t
|
||||
|
||||
|
||||
def rst_fmt(text, fmt):
|
||||
''' helper for Jinja2 to do format strings '''
|
||||
|
||||
return fmt % (text)
|
||||
|
||||
|
||||
def rst_xline(width, char="="):
|
||||
''' return a restructured text line of a given length '''
|
||||
|
||||
return char * width
|
@ -0,0 +1,98 @@
|
||||
# Copyright (c) 2019 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# key: The name of the key as defined in galaxy.yml
|
||||
# description: Comment/info on the key to be used as the generated doc and auto generated skeleton galaxy.yml file
|
||||
# required: Whether the key is required (default is no)
|
||||
# type: The type of value that can be set, aligns to the values in the plugin formatter
|
||||
---
|
||||
- key: namespace
|
||||
description:
|
||||
- The namespace of the collection.
|
||||
- This can be a company/brand/organization or product namespace under which all content lives.
|
||||
- May only contain alphanumeric characters and underscores. Additionally namespaces cannot start with underscores or
|
||||
numbers and cannot contain consecutive underscores.
|
||||
required: yes
|
||||
type: str
|
||||
|
||||
- key: name
|
||||
description:
|
||||
- The name of the collection.
|
||||
- Has the same character restrictions as C(namespace).
|
||||
required: yes
|
||||
type: str
|
||||
|
||||
- key: version
|
||||
description:
|
||||
- The version of the collection.
|
||||
- Must be compatible with semantic versioning.
|
||||
required: yes
|
||||
type: str
|
||||
|
||||
- key: readme
|
||||
description:
|
||||
- The path to the Markdown (.md) readme file.
|
||||
- This path is relative to the root of the collection.
|
||||
required: yes
|
||||
type: str
|
||||
|
||||
- key: authors
|
||||
description:
|
||||
- A list of the collection's content authors.
|
||||
- Can be just the name or in the format 'Full Name <email> (url) @nicks:irc/im.site#channel'.
|
||||
required: yes
|
||||
type: list
|
||||
|
||||
- key: description
|
||||
description:
|
||||
- A short summary description of the collection.
|
||||
type: str
|
||||
|
||||
- key: license
|
||||
description:
|
||||
- Either a single license or a list of licenses for content inside of a collection.
|
||||
- Ansible Galaxy currently only accepts L(SPDX,https://spdx.org/licenses/) licenses
|
||||
- This key is mutually exclusive with C(license_file).
|
||||
type: list
|
||||
|
||||
- key: license_file
|
||||
description:
|
||||
- The path to the license file for the collection.
|
||||
- This path is relative to the root of the collection.
|
||||
- This key is mutually exclusive with C(license).
|
||||
type: str
|
||||
|
||||
- key: tags
|
||||
description:
|
||||
- A list of tags you want to associate with the collection for indexing/searching.
|
||||
- A tag name has the same character requirements as C(namespace) and C(name).
|
||||
type: list
|
||||
|
||||
- key: dependencies
|
||||
description:
|
||||
- Collections that this collection requires to be installed for it to be usable.
|
||||
- The key of the dict is the collection label C(namespace.name).
|
||||
- The value is a version range
|
||||
L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification).
|
||||
- Multiple version range specifiers can be set and are separated by C(,).
|
||||
type: dict
|
||||
|
||||
- key: repository
|
||||
description:
|
||||
- The URL of the originating SCM repository.
|
||||
type: str
|
||||
|
||||
- key: documentation
|
||||
description:
|
||||
- The URL to any online docs.
|
||||
type: str
|
||||
|
||||
- key: homepage
|
||||
description:
|
||||
- The URL to the homepage of the collection/project.
|
||||
type: str
|
||||
|
||||
- key: issues
|
||||
description:
|
||||
- The URL to the collection issue tracker.
|
||||
type: str
|
@ -1,3 +1,3 @@
|
||||
# Ansible Collection - {{ namespace }}.{{ collection_name }}
|
||||
|
||||
Documentation for the collection.
|
||||
Documentation for the collection.
|
||||
|
@ -1,65 +1,11 @@
|
||||
### REQUIRED
|
||||
|
||||
# this can be a company/brand/organization or product namespace
|
||||
# under which all content lives
|
||||
namespace: {{ namespace }}
|
||||
|
||||
|
||||
# the designation of this specific collection
|
||||
name: {{ collection_name }}
|
||||
|
||||
|
||||
# semantic versioning compliant version designation
|
||||
version: 1.0.0
|
||||
|
||||
# the filename for the readme file which can be either markdown (.md)
|
||||
readme: README.md
|
||||
|
||||
|
||||
# a list of the collection's content authors
|
||||
# Ex: 'Full Name <email> (http://site) @nicks:irc/im/site#channel'
|
||||
authors:
|
||||
- {{ author }} <example@domain.com>
|
||||
|
||||
|
||||
### OPTIONAL but strongly advised
|
||||
|
||||
# short summary of the collection
|
||||
description: {{ description }}
|
||||
|
||||
|
||||
# Either a single valid SPDX license identifier or a list of valid SPDX license
|
||||
# identifiers, see https://spdx.org/licenses/. Could also set `license_file`
|
||||
# instead to point to the file the specifies the license in the collection
|
||||
# directory.
|
||||
license: {{ license }}
|
||||
|
||||
|
||||
# list of keywords you want to associate the collection
|
||||
# with for indexing/search systems
|
||||
tags: []
|
||||
|
||||
|
||||
# A dict of dependencies. A dependency is another collection
|
||||
# this collection requires to be installed for it to be usable.
|
||||
# The key of the dict is the collection label (namespace.name)
|
||||
# and the value is a spec for the semver version required.
|
||||
dependencies: {}
|
||||
|
||||
|
||||
### URLs
|
||||
|
||||
# url of originating SCM repository
|
||||
repository: {{ repository_url }}
|
||||
|
||||
|
||||
# url to online docs
|
||||
documentation: {{ documentation_url }}
|
||||
|
||||
|
||||
# homepage of the collection/project
|
||||
homepage: {{ homepage_url }}
|
||||
|
||||
|
||||
# issue tracker url
|
||||
issues: {{ issue_tracker_url }}
|
||||
{% for option in required_config %}
|
||||
{{ option.description | comment_ify }}
|
||||
{{ {option.key: option.value} | to_yaml }}
|
||||
{% endfor %}
|
||||
|
||||
### OPTIONAL but strongly recommended
|
||||
{% for option in optional_config %}
|
||||
{{ option.description | comment_ify }}
|
||||
{{ {option.key: option.value} | to_yaml }}
|
||||
{% endfor %}
|
||||
|
Loading…
Reference in New Issue