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 }}
|
# Ansible Collection - {{ namespace }}.{{ collection_name }}
|
||||||
|
|
||||||
Documentation for the collection.
|
Documentation for the collection.
|
||||||
|
@ -1,65 +1,11 @@
|
|||||||
### REQUIRED
|
### REQUIRED
|
||||||
|
{% for option in required_config %}
|
||||||
# this can be a company/brand/organization or product namespace
|
{{ option.description | comment_ify }}
|
||||||
# under which all content lives
|
{{ {option.key: option.value} | to_yaml }}
|
||||||
namespace: {{ namespace }}
|
{% endfor %}
|
||||||
|
|
||||||
|
### OPTIONAL but strongly recommended
|
||||||
# the designation of this specific collection
|
{% for option in optional_config %}
|
||||||
name: {{ collection_name }}
|
{{ option.description | comment_ify }}
|
||||||
|
{{ {option.key: option.value} | to_yaml }}
|
||||||
|
{% endfor %}
|
||||||
# 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 }}
|
|
||||||
|
Loading…
Reference in New Issue