mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-24 03:11:24 -07:00
Refactor parsing of CLI args so that we can modify them in the base class
Implement tag and skip_tag handling in the CLI() class. Change tag and skip_tag command line options to be accepted multiple times on the CLI and add them together rather than overwrite. * Make it configurable whether to merge or overwrite multiple --tags arguments * Make the base CLI class an abstractbaseclass so we can implement functionality in parse() but still make subclasses implement it. * Deprecate the overwrite feature of --tags with a message that the default will change in 2.4 and go away in 2.5. * Add documentation for merge_multiple_cli_flags * Fix galaxy search so its tags argument does not conflict with generic tags * Unit tests and more integration tests for tags
This commit is contained in:
parent
9962245b92
commit
1efe782b46
15 changed files with 162 additions and 77 deletions
|
@ -179,17 +179,6 @@ different locations::
|
||||||
|
|
||||||
Most users will not need to use this feature. See :doc:`developing_plugins` for more details
|
Most users will not need to use this feature. See :doc:`developing_plugins` for more details
|
||||||
|
|
||||||
.. _stdout_callback:
|
|
||||||
|
|
||||||
stdout_callback
|
|
||||||
===============
|
|
||||||
|
|
||||||
.. versionadded:: 2.0
|
|
||||||
|
|
||||||
This setting allows you to override the default stdout callback for ansible-playbook::
|
|
||||||
|
|
||||||
stdout_callback = skippy
|
|
||||||
|
|
||||||
.. _callback_whitelist:
|
.. _callback_whitelist:
|
||||||
|
|
||||||
callback_whitelist
|
callback_whitelist
|
||||||
|
@ -523,6 +512,23 @@ different locations::
|
||||||
|
|
||||||
Most users will not need to use this feature. See :doc:`developing_plugins` for more details
|
Most users will not need to use this feature. See :doc:`developing_plugins` for more details
|
||||||
|
|
||||||
|
.. _merge_multiple_cli_tags:
|
||||||
|
|
||||||
|
merge_multiple_cli_tags
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. versionadded:: 2.3
|
||||||
|
|
||||||
|
This allows changing how multiple --tags and --skip-tags arguments are handled
|
||||||
|
on the command line. In Ansible up to and including 2.3, specifying --tags
|
||||||
|
more than once will only take the last value of --tags. Setting this config
|
||||||
|
value to True will mean that all of the --tags options will be merged
|
||||||
|
together. The same holds true for --skip-tags.
|
||||||
|
|
||||||
|
.. note:: The default value for this in 2.3 is False. In 2.4, the
|
||||||
|
default value will be True. After 2.4, the option is going away.
|
||||||
|
Multiple --tags and multiple --skip-tags will always be merged together.
|
||||||
|
|
||||||
.. _module_set_locale:
|
.. _module_set_locale:
|
||||||
|
|
||||||
module_set_locale
|
module_set_locale
|
||||||
|
@ -705,6 +711,17 @@ The default value for this setting is only for certain package managers, but it
|
||||||
Currently, this is only supported for modules that have a name parameter, and only when the item is the
|
Currently, this is only supported for modules that have a name parameter, and only when the item is the
|
||||||
only thing being passed to the parameter.
|
only thing being passed to the parameter.
|
||||||
|
|
||||||
|
.. _stdout_callback:
|
||||||
|
|
||||||
|
stdout_callback
|
||||||
|
===============
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
This setting allows you to override the default stdout callback for ansible-playbook::
|
||||||
|
|
||||||
|
stdout_callback = skippy
|
||||||
|
|
||||||
.. _cfg_strategy_plugins:
|
.. _cfg_strategy_plugins:
|
||||||
|
|
||||||
strategy_plugins
|
strategy_plugins
|
||||||
|
|
|
@ -261,6 +261,11 @@
|
||||||
# set to 0 for unlimited (RAM may suffer!).
|
# set to 0 for unlimited (RAM may suffer!).
|
||||||
#max_diff_size = 1048576
|
#max_diff_size = 1048576
|
||||||
|
|
||||||
|
# This controls how ansible handles multiple --tags and --skip-tags arguments
|
||||||
|
# on the CLI. If this is True then multiple arguments are merged together. If
|
||||||
|
# it is False, then the last specified argument is used and the others are ignored.
|
||||||
|
#merge_multiple_cli_flags = False
|
||||||
|
|
||||||
[privilege_escalation]
|
[privilege_escalation]
|
||||||
#become=True
|
#become=True
|
||||||
#become_method=sudo
|
#become_method=sudo
|
||||||
|
|
|
@ -30,9 +30,11 @@ import re
|
||||||
import getpass
|
import getpass
|
||||||
import signal
|
import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
from ansible.release import __version__
|
from ansible.release import __version__
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
|
from ansible.compat.six import with_metaclass
|
||||||
from ansible.errors import AnsibleError, AnsibleOptionsError
|
from ansible.errors import AnsibleError, AnsibleOptionsError
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
|
@ -89,7 +91,7 @@ class InvalidOptsParser(SortedOptParser):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CLI(object):
|
class CLI(with_metaclass(ABCMeta, object)):
|
||||||
''' code behind bin/ansible* programs '''
|
''' code behind bin/ansible* programs '''
|
||||||
|
|
||||||
VALID_ACTIONS = ['No Actions']
|
VALID_ACTIONS = ['No Actions']
|
||||||
|
@ -144,10 +146,13 @@ class CLI(object):
|
||||||
fn = getattr(self, "execute_%s" % self.action)
|
fn = getattr(self, "execute_%s" % self.action)
|
||||||
fn()
|
fn()
|
||||||
|
|
||||||
def parse(self):
|
@abstractmethod
|
||||||
raise Exception("Need to implement!")
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
"""Run the ansible command
|
||||||
|
|
||||||
|
Subclasses must implement this method. It does the actual work of
|
||||||
|
running an Ansible command.
|
||||||
|
"""
|
||||||
|
|
||||||
if self.options.verbosity > 0:
|
if self.options.verbosity > 0:
|
||||||
if C.CONFIG_FILE:
|
if C.CONFIG_FILE:
|
||||||
|
@ -155,7 +160,6 @@ class CLI(object):
|
||||||
else:
|
else:
|
||||||
display.display(u"No config file found; using defaults")
|
display.display(u"No config file found; using defaults")
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ask_vault_passwords(ask_new_vault_pass=False, rekey=False):
|
def ask_vault_passwords(ask_new_vault_pass=False, rekey=False):
|
||||||
''' prompt for vault password and/or password change '''
|
''' prompt for vault password and/or password change '''
|
||||||
|
@ -314,9 +318,9 @@ class CLI(object):
|
||||||
action="callback", callback=CLI.expand_tilde, type=str)
|
action="callback", callback=CLI.expand_tilde, type=str)
|
||||||
|
|
||||||
if subset_opts:
|
if subset_opts:
|
||||||
parser.add_option('-t', '--tags', dest='tags', default='all',
|
parser.add_option('-t', '--tags', dest='tags', default=[], action='append',
|
||||||
help="only run plays and tasks tagged with these values")
|
help="only run plays and tasks tagged with these values")
|
||||||
parser.add_option('--skip-tags', dest='skip_tags',
|
parser.add_option('--skip-tags', dest='skip_tags', default=[], action='append',
|
||||||
help="only run plays and tasks whose tags do not match these values")
|
help="only run plays and tasks whose tags do not match these values")
|
||||||
|
|
||||||
if output_opts:
|
if output_opts:
|
||||||
|
@ -405,6 +409,55 @@ class CLI(object):
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def parse(self):
|
||||||
|
"""Parse the command line args
|
||||||
|
|
||||||
|
This method parses the command line arguments. It uses the parser
|
||||||
|
stored in the self.parser attribute and saves the args and options in
|
||||||
|
self.args and self.options respectively.
|
||||||
|
|
||||||
|
Subclasses need to implement this method. They will usually create
|
||||||
|
a base_parser, add their own options to the base_parser, and then call
|
||||||
|
this method to do the actual parsing. An implementation will look
|
||||||
|
something like this::
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
parser = super(MyCLI, self).base_parser(usage="My Ansible CLI", inventory_opts=True)
|
||||||
|
parser.add_option('--my-option', dest='my_option', action='store')
|
||||||
|
self.parser = parser
|
||||||
|
super(MyCLI, self).parse()
|
||||||
|
# If some additional transformations are needed for the
|
||||||
|
# arguments and options, do it here.
|
||||||
|
"""
|
||||||
|
self.options, self.args = self.parser.parse_args(self.args[1:])
|
||||||
|
if hasattr(self.options, 'tags') and not self.options.tags:
|
||||||
|
# optparse defaults does not do what's expected
|
||||||
|
self.options.tags = ['all']
|
||||||
|
if hasattr(self.options, 'tags') and self.options.tags:
|
||||||
|
if not C.MERGE_MULTIPLE_CLI_TAGS:
|
||||||
|
if len(self.options.tags) > 1:
|
||||||
|
display.deprecated('Specifying --tags multiple times on the command line currently uses the last specified value. In 2.4, values will be merged instead. Set merge_multiple_cli_tags=True in ansible.cfg to get this behavior now.', version=2.5, removed=False)
|
||||||
|
self.options.tags = [self.options.tags[-1]]
|
||||||
|
|
||||||
|
tags = set()
|
||||||
|
for tag_set in self.options.tags:
|
||||||
|
for tag in tag_set.split(u','):
|
||||||
|
tags.add(tag.strip())
|
||||||
|
self.options.tags = list(tags)
|
||||||
|
|
||||||
|
if hasattr(self.options, 'skip_tags') and self.options.skip_tags:
|
||||||
|
if not C.MERGE_MULTIPLE_CLI_TAGS:
|
||||||
|
if len(self.options.skip_tags) > 1:
|
||||||
|
display.deprecated('Specifying --skip-tags multiple times on the command line currently uses the last specified value. In 2.4, values will be merged instead. Set merge_multiple_cli_tags=True in ansible.cfg to get this behavior now.', version=2.5, removed=False)
|
||||||
|
self.options.skip_tags = [self.options.skip_tags[-1]]
|
||||||
|
|
||||||
|
skip_tags = set()
|
||||||
|
for tag_set in self.options.skip_tags:
|
||||||
|
for tag in tag_set.split(u','):
|
||||||
|
skip_tags.add(tag.strip())
|
||||||
|
self.options.skip_tags = list(skip_tags)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def version(prog):
|
def version(prog):
|
||||||
''' return ansible version '''
|
''' return ansible version '''
|
||||||
|
|
|
@ -72,7 +72,7 @@ class AdHocCLI(CLI):
|
||||||
help="module name to execute (default=%s)" % C.DEFAULT_MODULE_NAME,
|
help="module name to execute (default=%s)" % C.DEFAULT_MODULE_NAME,
|
||||||
default=C.DEFAULT_MODULE_NAME)
|
default=C.DEFAULT_MODULE_NAME)
|
||||||
|
|
||||||
self.options, self.args = self.parser.parse_args(self.args[1:])
|
super(AdHocCLI, self).parse()
|
||||||
|
|
||||||
if len(self.args) < 1:
|
if len(self.args) < 1:
|
||||||
raise AnsibleOptionsError("Missing target hosts")
|
raise AnsibleOptionsError("Missing target hosts")
|
||||||
|
@ -82,8 +82,6 @@ class AdHocCLI(CLI):
|
||||||
display.verbosity = self.options.verbosity
|
display.verbosity = self.options.verbosity
|
||||||
self.validate_conflicts(runas_opts=True, vault_opts=True, fork_opts=True)
|
self.validate_conflicts(runas_opts=True, vault_opts=True, fork_opts=True)
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _play_ds(self, pattern, async, poll):
|
def _play_ds(self, pattern, async, poll):
|
||||||
check_raw = self.options.module_name in ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw')
|
check_raw = self.options.module_name in ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw')
|
||||||
return dict(
|
return dict(
|
||||||
|
|
|
@ -94,13 +94,12 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
||||||
help="one-step-at-a-time: confirm each task before running")
|
help="one-step-at-a-time: confirm each task before running")
|
||||||
|
|
||||||
self.parser.set_defaults(cwd='*')
|
self.parser.set_defaults(cwd='*')
|
||||||
self.options, self.args = self.parser.parse_args(self.args[1:])
|
|
||||||
|
super(AdHocCLI, self).parse()
|
||||||
|
|
||||||
display.verbosity = self.options.verbosity
|
display.verbosity = self.options.verbosity
|
||||||
self.validate_conflicts(runas_opts=True, vault_opts=True, fork_opts=True)
|
self.validate_conflicts(runas_opts=True, vault_opts=True, fork_opts=True)
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_names(self):
|
def get_names(self):
|
||||||
return dir(self)
|
return dir(self)
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,8 @@ class DocCLI(CLI):
|
||||||
self.parser.add_option("-s", "--snippet", action="store_true", default=False, dest='show_snippet',
|
self.parser.add_option("-s", "--snippet", action="store_true", default=False, dest='show_snippet',
|
||||||
help='Show playbook snippet for specified module(s)')
|
help='Show playbook snippet for specified module(s)')
|
||||||
|
|
||||||
self.options, self.args = self.parser.parse_args(self.args[1:])
|
super(DocCLI, self).parse()
|
||||||
|
|
||||||
display.verbosity = self.options.verbosity
|
display.verbosity = self.options.verbosity
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -100,7 +100,7 @@ class GalaxyCLI(CLI):
|
||||||
elif self.action == "search":
|
elif self.action == "search":
|
||||||
self.parser.set_usage("usage: %prog search [searchterm1 searchterm2] [--galaxy-tags galaxy_tag1,galaxy_tag2] [--platforms platform1,platform2] [--author username]")
|
self.parser.set_usage("usage: %prog search [searchterm1 searchterm2] [--galaxy-tags galaxy_tag1,galaxy_tag2] [--platforms platform1,platform2] [--author username]")
|
||||||
self.parser.add_option('--platforms', dest='platforms', help='list of OS platforms to filter by')
|
self.parser.add_option('--platforms', dest='platforms', help='list of OS platforms to filter by')
|
||||||
self.parser.add_option('--galaxy-tags', dest='tags', help='list of galaxy tags to filter by')
|
self.parser.add_option('--galaxy-tags', dest='galaxy_tags', help='list of galaxy tags to filter by')
|
||||||
self.parser.add_option('--author', dest='author', help='GitHub username')
|
self.parser.add_option('--author', dest='author', help='GitHub username')
|
||||||
elif self.action == "setup":
|
elif self.action == "setup":
|
||||||
self.parser.set_usage("usage: %prog setup [options] source github_user github_repo secret")
|
self.parser.set_usage("usage: %prog setup [options] source github_user github_repo secret")
|
||||||
|
@ -120,10 +120,10 @@ class GalaxyCLI(CLI):
|
||||||
if self.action in ("init","install"):
|
if self.action in ("init","install"):
|
||||||
self.parser.add_option('-f', '--force', dest='force', action='store_true', default=False, help='Force overwriting an existing role')
|
self.parser.add_option('-f', '--force', dest='force', action='store_true', default=False, help='Force overwriting an existing role')
|
||||||
|
|
||||||
self.options, self.args = self.parser.parse_args(self.args[1:])
|
super(GalaxyCLI, self).parse()
|
||||||
|
|
||||||
display.verbosity = self.options.verbosity
|
display.verbosity = self.options.verbosity
|
||||||
self.galaxy = Galaxy(self.options)
|
self.galaxy = Galaxy(self.options)
|
||||||
return True
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
|
@ -505,11 +505,11 @@ class GalaxyCLI(CLI):
|
||||||
terms.append(self.args.pop())
|
terms.append(self.args.pop())
|
||||||
search = '+'.join(terms[::-1])
|
search = '+'.join(terms[::-1])
|
||||||
|
|
||||||
if not search and not self.options.platforms and not self.options.tags and not self.options.author:
|
if not search and not self.options.platforms and not self.options.galaxy_tags and not self.options.author:
|
||||||
raise AnsibleError("Invalid query. At least one search term, platform, galaxy tag or author must be provided.")
|
raise AnsibleError("Invalid query. At least one search term, platform, galaxy tag or author must be provided.")
|
||||||
|
|
||||||
response = self.api.search_roles(search, platforms=self.options.platforms,
|
response = self.api.search_roles(search, platforms=self.options.platforms,
|
||||||
tags=self.options.tags, author=self.options.author, page_size=page_size)
|
tags=self.options.galaxy_tags, author=self.options.author, page_size=page_size)
|
||||||
|
|
||||||
if response['count'] == 0:
|
if response['count'] == 0:
|
||||||
display.display("No roles match your search.", color=C.COLOR_ERROR)
|
display.display("No roles match your search.", color=C.COLOR_ERROR)
|
||||||
|
|
|
@ -75,10 +75,8 @@ class PlaybookCLI(CLI):
|
||||||
parser.add_option('--start-at-task', dest='start_at_task',
|
parser.add_option('--start-at-task', dest='start_at_task',
|
||||||
help="start the playbook at the task matching this name")
|
help="start the playbook at the task matching this name")
|
||||||
|
|
||||||
self.options, self.args = parser.parse_args(self.args[1:])
|
|
||||||
|
|
||||||
|
|
||||||
self.parser = parser
|
self.parser = parser
|
||||||
|
super(PlaybookCLI, self).parse()
|
||||||
|
|
||||||
if len(self.args) == 0:
|
if len(self.args) == 0:
|
||||||
raise AnsibleOptionsError("You must specify a playbook file to run")
|
raise AnsibleOptionsError("You must specify a playbook file to run")
|
||||||
|
|
|
@ -30,6 +30,7 @@ import time
|
||||||
|
|
||||||
from ansible.errors import AnsibleOptionsError
|
from ansible.errors import AnsibleOptionsError
|
||||||
from ansible.cli import CLI
|
from ansible.cli import CLI
|
||||||
|
from ansible.module_utils._text import to_native
|
||||||
from ansible.plugins import module_loader
|
from ansible.plugins import module_loader
|
||||||
from ansible.utils.cmd_functions import run_cmd
|
from ansible.utils.cmd_functions import run_cmd
|
||||||
|
|
||||||
|
@ -100,7 +101,7 @@ class PullCLI(CLI):
|
||||||
# for pull we don't wan't a default
|
# for pull we don't wan't a default
|
||||||
self.parser.set_defaults(inventory=None)
|
self.parser.set_defaults(inventory=None)
|
||||||
|
|
||||||
self.options, self.args = self.parser.parse_args(self.args[1:])
|
super(PullCLI, self).parse()
|
||||||
|
|
||||||
if not self.options.dest:
|
if not self.options.dest:
|
||||||
hostname = socket.getfqdn()
|
hostname = socket.getfqdn()
|
||||||
|
@ -219,9 +220,9 @@ class PullCLI(CLI):
|
||||||
if self.options.ask_sudo_pass or self.options.ask_su_pass or self.options.become_ask_pass:
|
if self.options.ask_sudo_pass or self.options.ask_su_pass or self.options.become_ask_pass:
|
||||||
cmd += ' --ask-become-pass'
|
cmd += ' --ask-become-pass'
|
||||||
if self.options.skip_tags:
|
if self.options.skip_tags:
|
||||||
cmd += ' --skip-tags "%s"' % self.options.skip_tags
|
cmd += ' --skip-tags "%s"' % to_native(u','.join(self.options.skip_tags))
|
||||||
if self.options.tags:
|
if self.options.tags:
|
||||||
cmd += ' -t "%s"' % self.options.tags
|
cmd += ' -t "%s"' % to_native(u','.join(self.options.tags))
|
||||||
if self.options.subset:
|
if self.options.subset:
|
||||||
cmd += ' -l "%s"' % self.options.subset
|
cmd += ' -l "%s"' % self.options.subset
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -70,7 +70,8 @@ class VaultCLI(CLI):
|
||||||
elif self.action == "rekey":
|
elif self.action == "rekey":
|
||||||
self.parser.set_usage("usage: %prog rekey [options] file_name")
|
self.parser.set_usage("usage: %prog rekey [options] file_name")
|
||||||
|
|
||||||
self.options, self.args = self.parser.parse_args(self.args[1:])
|
super(VaultCLI, self).parse()
|
||||||
|
|
||||||
display.verbosity = self.options.verbosity
|
display.verbosity = self.options.verbosity
|
||||||
|
|
||||||
can_output = ['encrypt', 'decrypt']
|
can_output = ['encrypt', 'decrypt']
|
||||||
|
|
|
@ -151,6 +151,11 @@ DEFAULTS='defaults'
|
||||||
DEPRECATED_HOST_LIST = get_config(p, DEFAULTS, 'hostfile', 'ANSIBLE_HOSTS', '/etc/ansible/hosts', ispath=True)
|
DEPRECATED_HOST_LIST = get_config(p, DEFAULTS, 'hostfile', 'ANSIBLE_HOSTS', '/etc/ansible/hosts', ispath=True)
|
||||||
# this is not used since 0.5 but people might still have in config
|
# this is not used since 0.5 but people might still have in config
|
||||||
DEFAULT_PATTERN = get_config(p, DEFAULTS, 'pattern', None, None)
|
DEFAULT_PATTERN = get_config(p, DEFAULTS, 'pattern', None, None)
|
||||||
|
# If --tags or --skip-tags is given multiple times on the CLI and this is
|
||||||
|
# True, merge the lists of tags together. If False, let the last argument
|
||||||
|
# overwrite any previous ones. Behaviour is overwrite through 2.2. 2.3
|
||||||
|
# overwrites but prints deprecation. 2.4 the default is to merge.
|
||||||
|
MERGE_MULTIPLE_CLI_TAGS = get_config(p, DEFAULTS, 'merge_multiple_cli_tags', 'ANSIBLE_MERGE_MULTIPLE_CLI_TAGS', False, boolean=True)
|
||||||
|
|
||||||
#### GENERALLY CONFIGURABLE THINGS ####
|
#### GENERALLY CONFIGURABLE THINGS ####
|
||||||
DEFAULT_DEBUG = get_config(p, DEFAULTS, 'debug', 'ANSIBLE_DEBUG', False, boolean=True)
|
DEFAULT_DEBUG = get_config(p, DEFAULTS, 'debug', 'ANSIBLE_DEBUG', False, boolean=True)
|
||||||
|
|
|
@ -284,23 +284,16 @@ class PlayContext(Base):
|
||||||
if hasattr(options, 'timeout') and options.timeout:
|
if hasattr(options, 'timeout') and options.timeout:
|
||||||
self.timeout = int(options.timeout)
|
self.timeout = int(options.timeout)
|
||||||
|
|
||||||
# get the tag info from options, converting a comma-separated list
|
# get the tag info from options. We check to see if the options have
|
||||||
# of values into a proper list if need be. We check to see if the
|
# the attribute, as it is not always added via the CLI
|
||||||
# options have the attribute, as it is not always added via the CLI
|
|
||||||
if hasattr(options, 'tags'):
|
if hasattr(options, 'tags'):
|
||||||
if isinstance(options.tags, list):
|
self.only_tags.update(options.tags)
|
||||||
self.only_tags.update(options.tags)
|
|
||||||
elif isinstance(options.tags, string_types):
|
|
||||||
self.only_tags.update(options.tags.split(','))
|
|
||||||
|
|
||||||
if len(self.only_tags) == 0:
|
if len(self.only_tags) == 0:
|
||||||
self.only_tags = set(['all'])
|
self.only_tags = set(['all'])
|
||||||
|
|
||||||
if hasattr(options, 'skip_tags'):
|
if hasattr(options, 'skip_tags'):
|
||||||
if isinstance(options.skip_tags, list):
|
self.skip_tags.update(options.skip_tags)
|
||||||
self.skip_tags.update(options.skip_tags)
|
|
||||||
elif isinstance(options.skip_tags, string_types):
|
|
||||||
self.skip_tags.update(options.skip_tags.split(','))
|
|
||||||
|
|
||||||
def set_task_and_variable_override(self, task, variables, templar):
|
def set_task_and_variable_override(self, task, variables, templar):
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -193,12 +193,19 @@ test_win_group3: setup
|
||||||
ansible-playbook test_win_group3.yml -i inventory.winrm -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)
|
ansible-playbook test_win_group3.yml -i inventory.winrm -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)
|
||||||
|
|
||||||
test_tags: setup
|
test_tags: setup
|
||||||
|
# Run these using en_US.UTF-8 because list-tasks is a user output function and so it tailors its output to the user's locale. For unicode tags, this means replacing non-ascii chars with "?"
|
||||||
# Run everything by default
|
# Run everything by default
|
||||||
[ "$$(ansible-playbook --list-tasks test_tags.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v | fgrep Task_with | xargs)" = "Task_with_tag TAGS: [tag] Task_with_always_tag TAGS: [always] Task_without_tag TAGS: []" ]
|
[ "$$(LC_ALL=en_US.UTF-8 ansible-playbook --list-tasks test_tags.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v | fgrep Task_with | xargs)" = "Task_with_tag TAGS: [tag] Task_with_always_tag TAGS: [always] Task_with_unicode_tag TAGS: [くらとみ] Task_with_list_of_tags TAGS: [café, press] Task_without_tag TAGS: []" ]
|
||||||
# Run the exact tags, and always
|
# Run the exact tags, and always
|
||||||
[ "$$(ansible-playbook --list-tasks --tags tag test_tags.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v | fgrep Task_with | xargs)" = "Task_with_tag TAGS: [tag] Task_with_always_tag TAGS: [always]" ]
|
[ "$$(LC_ALL=en_US.UTF-8 ansible-playbook --list-tasks --tags tag test_tags.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v | fgrep Task_with | xargs)" = "Task_with_tag TAGS: [tag] Task_with_always_tag TAGS: [always]" ]
|
||||||
# Skip one tag
|
# Skip one tag
|
||||||
[ "$$(ansible-playbook --list-tasks --skip-tags tag test_tags.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v | fgrep Task_with | xargs)" = "Task_with_always_tag TAGS: [always] Task_without_tag TAGS: []" ]
|
[ "$$(LC_ALL=en_US.UTF-8 ansible-playbook --list-tasks --skip-tags tag test_tags.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v | fgrep Task_with | xargs)" = "Task_with_always_tag TAGS: [always] Task_with_unicode_tag TAGS: [くらとみ] Task_with_list_of_tags TAGS: [café, press] Task_without_tag TAGS: []" ]
|
||||||
|
# Skip a unicode tag
|
||||||
|
[ "$$(LC_ALL=en_US.UTF-8 ansible-playbook --list-tasks --skip-tags くらとみ test_tags.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v | fgrep Task_with | xargs)" = "Task_with_tag TAGS: [tag] Task_with_always_tag TAGS: [always] Task_with_list_of_tags TAGS: [café, press] Task_without_tag TAGS: []" ]
|
||||||
|
# Run just a unicode tag and always
|
||||||
|
[ "$$(LC_ALL=en_US.UTF-8 ansible-playbook --list-tasks --tags くらとみ test_tags.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v | fgrep Task_with | xargs)" = "Task_with_always_tag TAGS: [always] Task_with_unicode_tag TAGS: [くらとみ]" ]
|
||||||
|
# Run a tag from a list of tags and always
|
||||||
|
[ "$$(LC_ALL=en_US.UTF-8 ansible-playbook --list-tasks --tags café test_tags.yml -i $(INVENTORY) -e outputdir=$(TEST_DIR) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v | fgrep Task_with | xargs)" = "Task_with_always_tag TAGS: [always] Task_with_list_of_tags TAGS: [café, press]" ]
|
||||||
|
|
||||||
blocks: setup
|
blocks: setup
|
||||||
# remove old output log
|
# remove old output log
|
||||||
|
|
|
@ -10,6 +10,14 @@
|
||||||
- name: Task_with_always_tag
|
- name: Task_with_always_tag
|
||||||
debug: msg=
|
debug: msg=
|
||||||
tags: always
|
tags: always
|
||||||
|
- name: Task_with_unicode_tag
|
||||||
|
debug: msg=
|
||||||
|
tags: くらとみ
|
||||||
|
- name: Task_with_list_of_tags
|
||||||
|
debug: msg=
|
||||||
|
tags:
|
||||||
|
- café
|
||||||
|
- press
|
||||||
- name: Task_without_tag
|
- name: Task_without_tag
|
||||||
debug: msg=
|
debug: msg=
|
||||||
|
|
||||||
|
|
|
@ -154,12 +154,11 @@ class TestGalaxy(unittest.TestCase):
|
||||||
|
|
||||||
def run_parse_common(self, galaxycli_obj, action):
|
def run_parse_common(self, galaxycli_obj, action):
|
||||||
with patch.object(ansible.cli.SortedOptParser, "set_usage") as mocked_usage:
|
with patch.object(ansible.cli.SortedOptParser, "set_usage") as mocked_usage:
|
||||||
galaxy_parser = galaxycli_obj.parse()
|
galaxycli_obj.parse()
|
||||||
|
|
||||||
# checking that the common results of parse() for all possible actions have been created/called
|
# checking that the common results of parse() for all possible actions have been created/called
|
||||||
self.assertTrue(galaxy_parser)
|
self.assertIsInstance(galaxycli_obj.parser, ansible.cli.SortedOptParser)
|
||||||
self.assertTrue(isinstance(galaxycli_obj.parser, ansible.cli.SortedOptParser))
|
self.assertIsInstance(galaxycli_obj.galaxy, ansible.galaxy.Galaxy)
|
||||||
self.assertTrue(isinstance(galaxycli_obj.galaxy, ansible.galaxy.Galaxy))
|
|
||||||
if action in ['import', 'delete']:
|
if action in ['import', 'delete']:
|
||||||
formatted_call = 'usage: %prog ' + action + ' [options] github_user github_repo'
|
formatted_call = 'usage: %prog ' + action + ' [options] github_user github_repo'
|
||||||
elif action == 'info':
|
elif action == 'info':
|
||||||
|
@ -194,61 +193,61 @@ class TestGalaxy(unittest.TestCase):
|
||||||
# testing action 'delete'
|
# testing action 'delete'
|
||||||
gc = GalaxyCLI(args=["delete", "-c"])
|
gc = GalaxyCLI(args=["delete", "-c"])
|
||||||
self.run_parse_common(gc, "delete")
|
self.run_parse_common(gc, "delete")
|
||||||
self.assertTrue(gc.options.verbosity==0)
|
self.assertEqual(gc.options.verbosity, 0)
|
||||||
|
|
||||||
# testing action 'import'
|
# testing action 'import'
|
||||||
gc = GalaxyCLI(args=["import", "-c"])
|
gc = GalaxyCLI(args=["import", "-c"])
|
||||||
self.run_parse_common(gc, "import")
|
self.run_parse_common(gc, "import")
|
||||||
self.assertTrue(gc.options.wait==True)
|
self.assertEqual(gc.options.wait, True)
|
||||||
self.assertTrue(gc.options.reference==None)
|
self.assertEqual(gc.options.reference, None)
|
||||||
self.assertTrue(gc.options.check_status==False)
|
self.assertEqual(gc.options.check_status, False)
|
||||||
self.assertTrue(gc.options.verbosity==0)
|
self.assertEqual(gc.options.verbosity, 0)
|
||||||
|
|
||||||
# testing action 'info'
|
# testing action 'info'
|
||||||
gc = GalaxyCLI(args=["info", "-c"])
|
gc = GalaxyCLI(args=["info", "-c"])
|
||||||
self.run_parse_common(gc, "info")
|
self.run_parse_common(gc, "info")
|
||||||
self.assertTrue(gc.options.offline==False)
|
self.assertEqual(gc.options.offline, False)
|
||||||
|
|
||||||
# testing action 'init'
|
# testing action 'init'
|
||||||
gc = GalaxyCLI(args=["init", "-c"])
|
gc = GalaxyCLI(args=["init", "-c"])
|
||||||
self.run_parse_common(gc, "init")
|
self.run_parse_common(gc, "init")
|
||||||
self.assertTrue(gc.options.offline==False)
|
self.assertEqual(gc.options.offline, False)
|
||||||
self.assertTrue(gc.options.force==False)
|
self.assertEqual(gc.options.force, False)
|
||||||
|
|
||||||
# testing action 'install'
|
# testing action 'install'
|
||||||
gc = GalaxyCLI(args=["install", "-c"])
|
gc = GalaxyCLI(args=["install", "-c"])
|
||||||
self.run_parse_common(gc, "install")
|
self.run_parse_common(gc, "install")
|
||||||
self.assertTrue(gc.options.ignore_errors==False)
|
self.assertEqual(gc.options.ignore_errors, False)
|
||||||
self.assertTrue(gc.options.no_deps==False)
|
self.assertEqual(gc.options.no_deps, False)
|
||||||
self.assertTrue(gc.options.role_file==None)
|
self.assertEqual(gc.options.role_file, None)
|
||||||
self.assertTrue(gc.options.force==False)
|
self.assertEqual(gc.options.force, False)
|
||||||
|
|
||||||
# testing action 'list'
|
# testing action 'list'
|
||||||
gc = GalaxyCLI(args=["list", "-c"])
|
gc = GalaxyCLI(args=["list", "-c"])
|
||||||
self.run_parse_common(gc, "list")
|
self.run_parse_common(gc, "list")
|
||||||
self.assertTrue(gc.options.verbosity==0)
|
self.assertEqual(gc.options.verbosity, 0)
|
||||||
|
|
||||||
# testing action 'login'
|
# testing action 'login'
|
||||||
gc = GalaxyCLI(args=["login", "-c"])
|
gc = GalaxyCLI(args=["login", "-c"])
|
||||||
self.run_parse_common(gc, "login")
|
self.run_parse_common(gc, "login")
|
||||||
self.assertTrue(gc.options.verbosity==0)
|
self.assertEqual(gc.options.verbosity, 0)
|
||||||
self.assertTrue(gc.options.token==None)
|
self.assertEqual(gc.options.token, None)
|
||||||
|
|
||||||
# testing action 'remove'
|
# testing action 'remove'
|
||||||
gc = GalaxyCLI(args=["remove", "-c"])
|
gc = GalaxyCLI(args=["remove", "-c"])
|
||||||
self.run_parse_common(gc, "remove")
|
self.run_parse_common(gc, "remove")
|
||||||
self.assertTrue(gc.options.verbosity==0)
|
self.assertEqual(gc.options.verbosity, 0)
|
||||||
|
|
||||||
# testing action 'search'
|
# testing action 'search'
|
||||||
gc = GalaxyCLI(args=["search", "-c"])
|
gc = GalaxyCLI(args=["search", "-c"])
|
||||||
self.run_parse_common(gc, "search")
|
self.run_parse_common(gc, "search")
|
||||||
self.assertTrue(gc.options.platforms==None)
|
self.assertEqual(gc.options.platforms, None)
|
||||||
self.assertTrue(gc.options.tags==None)
|
self.assertEqual(gc.options.galaxy_tags, None)
|
||||||
self.assertTrue(gc.options.author==None)
|
self.assertEqual(gc.options.author, None)
|
||||||
|
|
||||||
# testing action 'setup'
|
# testing action 'setup'
|
||||||
gc = GalaxyCLI(args=["setup", "-c"])
|
gc = GalaxyCLI(args=["setup", "-c"])
|
||||||
self.run_parse_common(gc, "setup")
|
self.run_parse_common(gc, "setup")
|
||||||
self.assertTrue(gc.options.verbosity==0)
|
self.assertEqual(gc.options.verbosity, 0)
|
||||||
self.assertTrue(gc.options.remove_id==None)
|
self.assertEqual(gc.options.remove_id, None)
|
||||||
self.assertTrue(gc.options.setup_list==False)
|
self.assertEqual(gc.options.setup_list, False)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue