galaxy - add format options for collection list (#73474)

* Include all collections in single json object / yaml document
* Add tests
* For galaxy list yaml/json output, use dictionary of dictionaries instead of list
* Add tests for listing single collection in yaml / output format
* --output -> --format
* Add explicit test for listing collection in human format
* Fix bug where empty json object was emitted + add test
This commit is contained in:
Shane McDonald 2021-02-05 13:24:59 -05:00 committed by GitHub
parent d3f3784b86
commit 67f5bb39c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 0 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- Add ``--format`` CLI option to ``ansible-galaxy collection list`` which allows for ``human`` (default), ``yaml``, or ``json``. (https://github.com/ansible/ansible/pull/73474)

View file

@ -5,6 +5,7 @@
from __future__ import (absolute_import, division, print_function) from __future__ import (absolute_import, division, print_function)
__metaclass__ = type __metaclass__ = type
import json
import os.path import os.path
import re import re
import shutil import shutil
@ -301,6 +302,10 @@ class GalaxyCLI(CLI):
list_parser.add_argument(galaxy_type, help=galaxy_type.capitalize(), nargs='?', metavar=galaxy_type) list_parser.add_argument(galaxy_type, help=galaxy_type.capitalize(), nargs='?', metavar=galaxy_type)
if galaxy_type == 'collection':
list_parser.add_argument('--format', dest='output_format', choices=('human', 'yaml', 'json'), default='human',
help="Format to display the list of collections in.")
def add_search_options(self, parser, parents=None): def add_search_options(self, parser, parents=None):
search_parser = parser.add_parser('search', parents=parents, search_parser = parser.add_parser('search', parents=parents,
help='Search the Galaxy database by tags, platforms, author and multiple ' help='Search the Galaxy database by tags, platforms, author and multiple '
@ -1379,9 +1384,11 @@ class GalaxyCLI(CLI):
:param artifacts_manager: Artifacts manager. :param artifacts_manager: Artifacts manager.
""" """
output_format = context.CLIARGS['output_format']
collections_search_paths = set(context.CLIARGS['collections_path']) collections_search_paths = set(context.CLIARGS['collections_path'])
collection_name = context.CLIARGS['collection'] collection_name = context.CLIARGS['collection']
default_collections_path = AnsibleCollectionConfig.collection_paths default_collections_path = AnsibleCollectionConfig.collection_paths
collections_in_paths = {}
warnings = [] warnings = []
path_found = False path_found = False
@ -1428,6 +1435,13 @@ class GalaxyCLI(CLI):
except ValueError as val_err: except ValueError as val_err:
six.raise_from(AnsibleError(val_err), val_err) six.raise_from(AnsibleError(val_err), val_err)
if output_format in {'yaml', 'json'}:
collections_in_paths[collection_path] = {
collection.fqcn: {'version': collection.ver}
}
continue
fqcn_width, version_width = _get_collection_widths([collection]) fqcn_width, version_width = _get_collection_widths([collection])
_display_header(collection_path, 'Collection', 'Version', fqcn_width, version_width) _display_header(collection_path, 'Collection', 'Version', fqcn_width, version_width)
@ -1451,6 +1465,13 @@ class GalaxyCLI(CLI):
display.vvv("No collections found at {0}".format(collection_path)) display.vvv("No collections found at {0}".format(collection_path))
continue continue
if output_format in {'yaml', 'json'}:
collections_in_paths[collection_path] = {
collection.fqcn: {'version': collection.ver} for collection in collections
}
continue
# Display header # Display header
fqcn_width, version_width = _get_collection_widths(collections) fqcn_width, version_width = _get_collection_widths(collections)
_display_header(collection_path, 'Collection', 'Version', fqcn_width, version_width) _display_header(collection_path, 'Collection', 'Version', fqcn_width, version_width)
@ -1469,6 +1490,11 @@ class GalaxyCLI(CLI):
if not path_found: if not path_found:
raise AnsibleOptionsError("- None of the provided paths were usable. Please specify a valid path with --{0}s-path".format(context.CLIARGS['type'])) raise AnsibleOptionsError("- None of the provided paths were usable. Please specify a valid path with --{0}s-path".format(context.CLIARGS['type']))
if output_format == 'json':
display.display(json.dumps(collections_in_paths))
elif output_format == 'yaml':
display.display(yaml.safe_dump(collections_in_paths))
return 0 return 0
def execute_publish(self): def execute_publish(self):

View file

@ -31,6 +31,82 @@
- "'dev.collection2 placeholder' in list_result.stdout" - "'dev.collection2 placeholder' in list_result.stdout"
- "'dev.collection3 *' in list_result.stdout" - "'dev.collection3 *' in list_result.stdout"
- name: list collections in human format
command: ansible-galaxy collection list --format human
register: list_result_human
environment:
ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
- assert:
that:
- "'dev.collection1 *' in list_result_human.stdout"
# Note the version displayed is the 'placeholder' string rather than "*" since it is not falsey
- "'dev.collection2 placeholder' in list_result_human.stdout"
- "'dev.collection3 *' in list_result_human.stdout"
- name: list collections in yaml format
command: ansible-galaxy collection list --format yaml
register: list_result_yaml
environment:
ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
- assert:
that:
- "item.value | length == 3"
- "item.value['dev.collection1'].version == '*'"
- "item.value['dev.collection2'].version == 'placeholder'"
- "item.value['dev.collection3'].version == '*'"
with_dict: "{{ list_result_yaml.stdout | from_yaml }}"
- name: list collections in json format
command: ansible-galaxy collection list --format json
register: list_result_json
environment:
ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
- assert:
that:
- "item.value | length == 3"
- "item.value['dev.collection1'].version == '*'"
- "item.value['dev.collection2'].version == 'placeholder'"
- "item.value['dev.collection3'].version == '*'"
with_dict: "{{ list_result_json.stdout | from_json }}"
- name: list single collection in json format
command: "ansible-galaxy collection list {{ item.key }} --format json"
register: list_single_result_json
environment:
ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
with_dict: "{{ { 'dev.collection1': '*', 'dev.collection2': 'placeholder', 'dev.collection3': '*' } }}"
- assert:
that:
- "(item.stdout | from_json)[galaxy_dir + '/dev/ansible_collections'][item.item.key].version == item.item.value"
with_items: "{{ list_single_result_json.results }}"
- name: list single collection in yaml format
command: "ansible-galaxy collection list {{ item.key }} --format yaml"
register: list_single_result_yaml
environment:
ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev:{{ galaxy_dir }}/prod"
with_dict: "{{ { 'dev.collection1': '*', 'dev.collection2': 'placeholder', 'dev.collection3': '*' } }}"
- assert:
that:
- "(item.stdout | from_yaml)[galaxy_dir + '/dev/ansible_collections'][item.item.key].version == item.item.value"
with_items: "{{ list_single_result_json.results }}"
- name: test that no json is emitted when no collection paths are usable
command: "ansible-galaxy collection list --format json"
register: list_result_error
ignore_errors: True
environment:
ANSIBLE_COLLECTIONS_PATH: ""
- assert:
that:
- "'{}' not in list_result_error.stdout"
- name: install an artifact to the second collections path - name: install an artifact to the second collections path
command: ansible-galaxy collection install namespace1.name1 -s galaxy_ng {{ galaxy_verbosity }} -p "{{ galaxy_dir }}/prod" command: ansible-galaxy collection install namespace1.name1 -s galaxy_ng {{ galaxy_verbosity }} -p "{{ galaxy_dir }}/prod"
environment: environment:

View file

@ -41,6 +41,7 @@ def cliargs(collections_paths=None, collection_name=None):
'collections_path': collections_paths, 'collections_path': collections_paths,
'collection': collection_name, 'collection': collection_name,
'type': 'collection', 'type': 'collection',
'output_format': 'human'
} }