Accept list of paths in 'path' arg.
This adds the behavior of splitting the path positional argument on colons then processing each resulting string the same way that the path was being processed previous to this commit. * Adds a unit test to validate correct `path` parsing. * Adds a unit test to validate correct `path` parsing in the recursive case. * Documents the new behavior. Change-Id: I0f465e02077569352cd276a8366ead5bab0eb117
This commit is contained in:
parent
1db5ad59c1
commit
f0e53d34a1
@ -146,6 +146,19 @@ arguments after the job definition path. To update Foo1 and Foo2 run::
|
||||
|
||||
jenkins-jobs update /path/to/defs Foo1 Foo2
|
||||
|
||||
Passing Multiple Paths
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
It is possible to pass multiple paths to JJB using colons as a path separator on
|
||||
\*nix systems and semi-colons on Windows systems. For example::
|
||||
|
||||
jenkins-jobs test /path/to/global:/path/to/instance:/path/to/instance/project
|
||||
|
||||
This helps when structuring directory layouts as you may selectively include
|
||||
directories in different ways to suit different needs. If you maintain multiple
|
||||
Jenkins instances suited to various needs you may want to share configuration
|
||||
between those instances (global). Furthermore, there may be various ways you
|
||||
would like to structure jobs within a given instance.
|
||||
|
||||
|
||||
.. rubric:: Footnotes
|
||||
.. [#f1] The cache default location is at ``~/.cache/jenkins_jobs``, which
|
||||
|
@ -69,13 +69,15 @@ def create_parser():
|
||||
subparser = parser.add_subparsers(help='update, test or delete job',
|
||||
dest='command')
|
||||
parser_update = subparser.add_parser('update', parents=[recursive_parser])
|
||||
parser_update.add_argument('path', help='path to YAML file or directory')
|
||||
parser_update.add_argument('path', help='colon-separated list of paths to'
|
||||
' YAML files or directories')
|
||||
parser_update.add_argument('names', help='name(s) of job(s)', nargs='*')
|
||||
parser_update.add_argument('--delete-old', help='delete obsolete jobs',
|
||||
action='store_true',
|
||||
dest='delete_old', default=False,)
|
||||
parser_test = subparser.add_parser('test', parents=[recursive_parser])
|
||||
parser_test.add_argument('path', help='path to YAML file or directory',
|
||||
parser_test.add_argument('path', help='colon-separated list of paths to'
|
||||
' YAML files or directories',
|
||||
nargs='?', default=sys.stdin)
|
||||
parser_test.add_argument('-o', dest='output_dir', default=sys.stdout,
|
||||
help='path to output XML')
|
||||
@ -83,7 +85,8 @@ def create_parser():
|
||||
parser_delete = subparser.add_parser('delete')
|
||||
parser_delete.add_argument('name', help='name of job', nargs='+')
|
||||
parser_delete.add_argument('-p', '--path', default=None,
|
||||
help='path to YAML file or directory')
|
||||
help='colon-separated list of paths to'
|
||||
' YAML files or directories')
|
||||
subparser.add_parser('delete-all',
|
||||
help='delete *ALL* jobs from Jenkins server, '
|
||||
'including those not managed by Jenkins Job '
|
||||
@ -195,13 +198,19 @@ def execute(options, config):
|
||||
"Reading configuration from STDIN. Press %s to end input.",
|
||||
key)
|
||||
|
||||
# expand or convert options.path to a list
|
||||
if (getattr(options, 'recursive', False)
|
||||
or config.getboolean('job_builder', 'recursive')) and \
|
||||
os.path.isdir(options.path):
|
||||
options.path = recurse_path(options.path)
|
||||
else:
|
||||
options.path = [options.path]
|
||||
# take list of paths
|
||||
options.path = options.path.split(os.pathsep)
|
||||
|
||||
do_recurse = (getattr(options, 'recursive', False) or
|
||||
config.getboolean('job_builder', 'recursive'))
|
||||
|
||||
paths = []
|
||||
for path in options.path:
|
||||
if do_recurse and os.path.isdir(path):
|
||||
paths.extend(recurse_path(path))
|
||||
else:
|
||||
paths.append(path)
|
||||
options.path = paths
|
||||
|
||||
if options.command == 'delete':
|
||||
for job in options.name:
|
||||
|
10
tests/cmd/fixtures/multipath/multipath.yaml
Normal file
10
tests/cmd/fixtures/multipath/multipath.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
# this file is here to ensure the directory containing it is caught by git for
|
||||
# the sake of multipath testing.
|
||||
- job-template:
|
||||
name: 'herp-job'
|
||||
description: 'a simple job'
|
||||
|
||||
- project:
|
||||
name: herp-project
|
||||
jobs:
|
||||
- herp-job
|
@ -69,6 +69,83 @@ class CmdTests(testtools.TestCase):
|
||||
config.readfp(StringIO(cmd.DEFAULT_CONF))
|
||||
cmd.execute(args, config) # probably better to fail here
|
||||
|
||||
def test_multi_path(self):
|
||||
"""
|
||||
Run test mode and pass multiple paths.
|
||||
"""
|
||||
path_list = [os.path.join(self.fixtures_path, 'multipath'),
|
||||
self.fixtures_path]
|
||||
multipath = os.pathsep.join(path_list)
|
||||
args = self.parser.parse_args(['test', multipath])
|
||||
args.output_dir = mock.MagicMock()
|
||||
config = configparser.ConfigParser()
|
||||
config.readfp(StringIO(cmd.DEFAULT_CONF))
|
||||
cmd.execute(args, config)
|
||||
self.assertEqual(args.path, path_list)
|
||||
|
||||
@mock.patch('jenkins_jobs.cmd.Builder.update_job')
|
||||
@mock.patch('jenkins_jobs.cmd.os.path.isdir')
|
||||
@mock.patch('jenkins_jobs.cmd.os.walk')
|
||||
def test_recursive_multi_path(self, os_walk_mock, isdir_mock,
|
||||
update_job_mock):
|
||||
"""
|
||||
Run test mode and pass multiple paths with recursive path option.
|
||||
"""
|
||||
os_walk_return_values = {
|
||||
'/jjb_projects': [
|
||||
('/jjb_projects', ('dir1', 'dir2', 'dir3'), ()),
|
||||
('/jjb_projects/dir1', ('bar',), ()),
|
||||
('/jjb_projects/dir2', ('baz',), ()),
|
||||
('/jjb_projects/dir3', (), ()),
|
||||
('/jjb_projects/dir1/bar', (), ()),
|
||||
('/jjb_projects/dir2/baz', (), ()),
|
||||
],
|
||||
'/jjb_templates': [
|
||||
('/jjb_templates', ('dir1', 'dir2', 'dir3'), ()),
|
||||
('/jjb_templates/dir1', ('bar',), ()),
|
||||
('/jjb_templates/dir2', ('baz',), ()),
|
||||
('/jjb_templates/dir3', (), ()),
|
||||
('/jjb_templates/dir1/bar', (), ()),
|
||||
('/jjb_templates/dir2/baz', (), ()),
|
||||
],
|
||||
'/jjb_macros': [
|
||||
('/jjb_macros', ('dir1', 'dir2', 'dir3'), ()),
|
||||
('/jjb_macros/dir1', ('bar',), ()),
|
||||
('/jjb_macros/dir2', ('baz',), ()),
|
||||
('/jjb_macros/dir3', (), ()),
|
||||
('/jjb_macros/dir1/bar', (), ()),
|
||||
('/jjb_macros/dir2/baz', (), ()),
|
||||
],
|
||||
}
|
||||
|
||||
def os_walk_side_effects(path_name, topdown):
|
||||
return os_walk_return_values[path_name]
|
||||
|
||||
os_walk_mock.side_effect = os_walk_side_effects
|
||||
isdir_mock.return_value = True
|
||||
|
||||
path_list = os_walk_return_values.keys()
|
||||
paths = []
|
||||
for path in path_list:
|
||||
paths.extend([p for p, _, _ in os_walk_return_values[path]])
|
||||
|
||||
multipath = os.pathsep.join(path_list)
|
||||
|
||||
args = self.parser.parse_args(['test', '-r', multipath])
|
||||
args.output_dir = mock.MagicMock()
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.readfp(StringIO(cmd.DEFAULT_CONF))
|
||||
cmd.execute(args, config)
|
||||
|
||||
update_job_mock.assert_called_with(paths, [], output=args.output_dir)
|
||||
|
||||
args = self.parser.parse_args(['test', multipath])
|
||||
config.set('job_builder', 'recursive', 'True')
|
||||
cmd.execute(args, config)
|
||||
|
||||
update_job_mock.assert_called_with(paths, [], output=args.output_dir)
|
||||
|
||||
def test_console_output(self):
|
||||
"""
|
||||
Run test mode and verify that resulting XML gets sent to the console.
|
||||
|
Loading…
x
Reference in New Issue
Block a user