CLI: Add support for listing repository types
Similar to listing sites for a repository, this adds functionality for listing available types. Change-Id: I9e6399b56f0986003b61f1db0839ed21c6237cec
This commit is contained in:
parent
57a6c6a84e
commit
ab3228f2ed
|
@ -29,7 +29,7 @@ CONTEXT_SETTINGS = {
|
|||
'help_option_names': ['-h', '--help'],
|
||||
}
|
||||
|
||||
REPOSITORY_OPTION = click.option(
|
||||
MAIN_REPOSITORY_OPTION = click.option(
|
||||
'-r',
|
||||
'--site-repository',
|
||||
'site_repository',
|
||||
|
@ -49,6 +49,22 @@ EXTRA_REPOSITORY_OPTION = click.option(
|
|||
'site-definition for the site will be leveraged but can be overridden '
|
||||
'using -e global=/opt/global@revision.')
|
||||
|
||||
REPOSITORY_KEY_OPTION = click.option(
|
||||
'-k',
|
||||
'--repo-key',
|
||||
'repo_key',
|
||||
help='The SSH public key to use when cloning remote authenticated '
|
||||
'repositories.')
|
||||
|
||||
REPOSITORY_USERNAME_OPTION = click.option(
|
||||
'-u',
|
||||
'--repo-username',
|
||||
'repo_username',
|
||||
help=
|
||||
'The SSH username to use when cloning remote authenticated repositories '
|
||||
'specified in the site-definition file. Any occurrences of REPO_USERNAME '
|
||||
'will be replaced with this value.')
|
||||
|
||||
ALLOW_MISSING_SUBSTITUTIONS_OPTION = click.option(
|
||||
'-f',
|
||||
'--fail-on-missing-sub-src',
|
||||
|
@ -99,8 +115,12 @@ def main(*, verbose):
|
|||
|
||||
|
||||
@main.group(help='Commands related to repositories')
|
||||
@REPOSITORY_OPTION
|
||||
def repo(*, site_repository):
|
||||
@MAIN_REPOSITORY_OPTION
|
||||
# TODO(felipemonteiro): Support EXTRA_REPOSITORY_OPTION as well to be
|
||||
# able to lint multiple repos together.
|
||||
@REPOSITORY_USERNAME_OPTION
|
||||
@REPOSITORY_KEY_OPTION
|
||||
def repo(*, site_repository, repo_key, repo_username):
|
||||
"""Group for repo-level actions, which include:
|
||||
|
||||
* lint: lint all sites across the repository
|
||||
|
@ -108,6 +128,8 @@ def repo(*, site_repository):
|
|||
"""
|
||||
|
||||
config.set_site_repo(site_repository)
|
||||
config.set_repo_key(repo_key)
|
||||
config.set_repo_username(repo_username)
|
||||
|
||||
|
||||
def _lint_helper(*,
|
||||
|
@ -145,22 +167,10 @@ def lint_repo(*, fail_on_missing_sub_src, exclude_lint, warn_lint):
|
|||
|
||||
|
||||
@main.group(help='Commands related to sites')
|
||||
@REPOSITORY_OPTION
|
||||
@MAIN_REPOSITORY_OPTION
|
||||
@EXTRA_REPOSITORY_OPTION
|
||||
@click.option(
|
||||
'-k',
|
||||
'--repo-key',
|
||||
'repo_key',
|
||||
help='The SSH public key to use when cloning remote authenticated '
|
||||
'repositories.')
|
||||
@click.option(
|
||||
'-u',
|
||||
'--repo-username',
|
||||
'repo_username',
|
||||
help=
|
||||
'The SSH username to use when cloning remote authenticated repositories '
|
||||
'specified in the site-definition file. Any occurrences of REPO_USERNAME '
|
||||
'will be replaced with this value.')
|
||||
@REPOSITORY_USERNAME_OPTION
|
||||
@REPOSITORY_KEY_OPTION
|
||||
def site(*, site_repository, extra_repositories, repo_key, repo_username):
|
||||
"""Group for site-level actions, which include:
|
||||
|
||||
|
@ -238,7 +248,7 @@ def collect(*, save_location, validate, exclude_lint, warn_lint, site_name):
|
|||
'output_stream',
|
||||
type=click.File(mode='w'),
|
||||
default=sys.stdout,
|
||||
help='Where to output')
|
||||
help='Where to output. Defaults to sys.stdout.')
|
||||
def list_(*, output_stream):
|
||||
engine.repository.process_site_repository(update_config=True)
|
||||
engine.site.list_(output_stream)
|
||||
|
@ -251,7 +261,7 @@ def list_(*, output_stream):
|
|||
'output_stream',
|
||||
type=click.File(mode='w'),
|
||||
default=sys.stdout,
|
||||
help='Where to output')
|
||||
help='Where to output. Defaults to sys.stdout.')
|
||||
@click.argument('site_name')
|
||||
def show(*, output_stream, site_name):
|
||||
engine.repository.process_repositories(site_name)
|
||||
|
@ -265,7 +275,7 @@ def show(*, output_stream, site_name):
|
|||
'output_stream',
|
||||
type=click.File(mode='w'),
|
||||
default=sys.stdout,
|
||||
help='Where to output')
|
||||
help='Where to output. Defaults to sys.stdout.')
|
||||
@click.argument('site_name')
|
||||
def render(*, output_stream, site_name):
|
||||
engine.repository.process_repositories(site_name)
|
||||
|
@ -287,3 +297,34 @@ def lint_site(*, fail_on_missing_sub_src, exclude_lint, warn_lint, site_name):
|
|||
fail_on_missing_sub_src=fail_on_missing_sub_src,
|
||||
exclude_lint=exclude_lint,
|
||||
warn_lint=warn_lint)
|
||||
|
||||
|
||||
@main.group(help='Commands related to types')
|
||||
@MAIN_REPOSITORY_OPTION
|
||||
@EXTRA_REPOSITORY_OPTION
|
||||
@REPOSITORY_USERNAME_OPTION
|
||||
@REPOSITORY_KEY_OPTION
|
||||
def type(*, site_repository, extra_repositories, repo_key, repo_username):
|
||||
"""Group for repo-level actions, which include:
|
||||
|
||||
* list: list all types across the repository
|
||||
|
||||
"""
|
||||
config.set_site_repo(site_repository)
|
||||
config.set_extra_repo_store(extra_repositories or [])
|
||||
config.set_repo_key(repo_key)
|
||||
config.set_repo_username(repo_username)
|
||||
|
||||
|
||||
@type.command('list', help='List known types')
|
||||
@click.option(
|
||||
'-o',
|
||||
'--output',
|
||||
'output_stream',
|
||||
type=click.File(mode='w'),
|
||||
default=sys.stdout,
|
||||
help='Where to output. Defaults to sys.stdout.')
|
||||
def list_types(*, output_stream):
|
||||
"""List type names for a given repository."""
|
||||
engine.repository.process_site_repository(update_config=True)
|
||||
engine.type.list_types(output_stream)
|
||||
|
|
|
@ -19,7 +19,8 @@ except NameError:
|
|||
GLOBAL_CONTEXT = {
|
||||
'site_repo': './',
|
||||
'extra_repos': [],
|
||||
'site_path': 'site'
|
||||
'site_path': 'site',
|
||||
'type_path': 'type'
|
||||
}
|
||||
|
||||
|
||||
|
@ -85,3 +86,12 @@ def get_rel_site_path():
|
|||
def set_rel_site_path(p):
|
||||
p = p or 'site'
|
||||
GLOBAL_CONTEXT['site_path'] = p
|
||||
|
||||
|
||||
def get_rel_type_path():
|
||||
return GLOBAL_CONTEXT.get('type_path', 'type')
|
||||
|
||||
|
||||
def set_rel_type_path(p):
|
||||
p = p or 'type'
|
||||
GLOBAL_CONTEXT['type_path'] = p
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import csv
|
||||
import logging
|
||||
|
||||
from pegleg.engine import util
|
||||
|
||||
__all__ = ('list_types', )
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def list_types(output_stream):
|
||||
"""List type names for a given repository."""
|
||||
|
||||
# TODO(felipemonteiro): This should output a formatted table, not rows of
|
||||
# data without delimited columns.
|
||||
fieldnames = ['type_name']
|
||||
writer = csv.DictWriter(
|
||||
output_stream, fieldnames=fieldnames, delimiter=' ')
|
||||
for type_name in util.files.list_types():
|
||||
writer.writerow({'type_name': type_name})
|
|
@ -180,6 +180,18 @@ def list_sites(primary_repo_base=None):
|
|||
yield path
|
||||
|
||||
|
||||
def list_types(primary_repo_base=None):
|
||||
"""Get a list of type directories in the primary repo."""
|
||||
if not primary_repo_base:
|
||||
primary_repo_base = config.get_site_repo()
|
||||
full_type_path = os.path.join(primary_repo_base,
|
||||
config.get_rel_type_path())
|
||||
for path in os.listdir(full_type_path):
|
||||
joined_path = os.path.join(full_type_path, path)
|
||||
if os.path.isdir(joined_path):
|
||||
yield path
|
||||
|
||||
|
||||
def directory_for(*, path):
|
||||
for r in config.all_repos():
|
||||
if path.startswith(r):
|
||||
|
|
|
@ -244,3 +244,42 @@ class TestRepoCliActions(BaseCLIActionTest):
|
|||
# A successful result (while setting lint checks to exclude) should
|
||||
# output nothing.
|
||||
assert not result.output
|
||||
|
||||
|
||||
class TestTypeCliActions(BaseCLIActionTest):
|
||||
"""Tests type-level CLI actions."""
|
||||
|
||||
def test_list_types_using_remote_repo_url(self):
|
||||
"""Validates list types action using remote repo URL."""
|
||||
# Scenario:
|
||||
#
|
||||
# 1) List types (should clone repo automatically)
|
||||
|
||||
repo_url = 'https://github.com/openstack/%s@%s' % (self.repo_name,
|
||||
self.repo_rev)
|
||||
|
||||
# NOTE(felipemonteiro): Pegleg currently doesn't dump a table to stdout
|
||||
# for this CLI call so mock out the csv DictWriter to determine output.
|
||||
with mock.patch('pegleg.engine.type.csv.DictWriter') as mock_writer:
|
||||
result = self.runner.invoke(cli.type, ['-r', repo_url, 'list'])
|
||||
|
||||
assert result.exit_code == 0
|
||||
m_writer = mock_writer.return_value
|
||||
m_writer.writerow.assert_any_call({'type_name': 'foundry'})
|
||||
|
||||
def test_list_types_using_local_repo_path(self):
|
||||
"""Validates list types action using local repo path."""
|
||||
# Scenario:
|
||||
#
|
||||
# 1) List types for local repo path
|
||||
|
||||
repo_path = self.treasuremap_path
|
||||
|
||||
# NOTE(felipemonteiro): Pegleg currently doesn't dump a table to stdout
|
||||
# for this CLI call so mock out the csv DictWriter to determine output.
|
||||
with mock.patch('pegleg.engine.type.csv.DictWriter') as mock_writer:
|
||||
result = self.runner.invoke(cli.type, ['-r', repo_path, 'list'])
|
||||
|
||||
assert result.exit_code == 0
|
||||
m_writer = mock_writer.return_value
|
||||
m_writer.writerow.assert_any_call({'type_name': 'foundry'})
|
||||
|
|
Loading…
Reference in New Issue