Skip to content

Commit

Permalink
Skip build config section validation when passing no-build option
Browse files Browse the repository at this point in the history
  • Loading branch information
smasset committed Mar 13, 2018
1 parent 17fe8b9 commit d2e4ba7
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 14 deletions.
11 changes: 8 additions & 3 deletions compose/cli/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def project_from_options(project_dir, options):
environment=environment,
override_dir=options.get('--project-directory'),
compatibility=options.get('--compatibility'),
skipped_sections=['services.build'] if '--no-build' in options else []
)


Expand All @@ -63,9 +64,13 @@ def get_config_from_options(base_dir, options):
config_path = get_config_path_from_options(
base_dir, options, environment
)

skipped_sections = ['services.build'] if '--no-build' in options else []

return config.load(
config.find(base_dir, config_path, environment),
options.get('--compatibility')
options.get('--compatibility'),
skipped_sections
)


Expand Down Expand Up @@ -103,14 +108,14 @@ def get_client(environment, verbose=False, version=None, tls_config=None, host=N

def get_project(project_dir, config_path=None, project_name=None, verbose=False,
host=None, tls_config=None, environment=None, override_dir=None,
compatibility=False):
compatibility=False, skipped_sections=[]):
if not environment:
environment = Environment.from_env_file(project_dir)
config_details = config.find(project_dir, config_path, environment, override_dir)
project_name = get_project_name(
config_details.working_dir, project_name, environment
)
config_data = config.load(config_details, compatibility)
config_data = config.load(config_details, compatibility, skipped_sections)

api_version = environment.get(
'COMPOSE_API_VERSION',
Expand Down
36 changes: 25 additions & 11 deletions compose/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,16 @@ def check_swarm_only_key(service_dicts, key):
check_swarm_only_key(service_dicts, 'configs')


def load(config_details, compatibility=False):
def filter_sections(parent_section, skipped_sections, separator='.'):
"""Filters a list of sections to skip based on their parent section
Return a list of sections under the given parent section
"""
return [parts[2] for parts in (section.partition(separator) for section in skipped_sections)
if separator == parts[1] and parent_section == parts[0]]


def load(config_details, compatibility=False, skipped_sections=[]):
"""Load the configuration from a working directory and a list of
configuration files. Files are loaded in order, and merged on top
of each other to create the final configuration.
Expand Down Expand Up @@ -394,7 +403,12 @@ def load(config_details, compatibility=False):
configs = load_mapping(
config_details.config_files, 'get_configs', 'Config', config_details.working_dir
)
service_dicts = load_services(config_details, main_file, compatibility)
service_dicts = load_services(
config_details,
main_file,
compatibility,
filter_sections('services', skipped_sections)
)

if main_file.version != V1:
for service_dict in service_dicts:
Expand Down Expand Up @@ -446,7 +460,7 @@ def validate_external(entity_type, name, config, version):
entity_type, name, ', '.join(k for k in config if k != 'external')))


def load_services(config_details, config_file, compatibility=False):
def load_services(config_details, config_file, compatibility=False, skipped_sections=[]):
def build_service(service_name, service_dict, service_names):
service_config = ServiceConfig.with_abs_paths(
config_details.working_dir,
Expand All @@ -456,10 +470,10 @@ def build_service(service_name, service_dict, service_names):
resolver = ServiceExtendsResolver(
service_config, config_file, environment=config_details.environment
)
service_dict = process_service(resolver.run())
service_dict = process_service(resolver.run(), skipped_sections)

service_config = service_config._replace(config=service_dict)
validate_service(service_config, service_names, config_file)
validate_service(service_config, service_names, config_file, skipped_sections)
service_dict = finalize_service(
service_config,
service_names,
Expand Down Expand Up @@ -687,10 +701,10 @@ def validate_extended_service_dict(service_dict, filename, service):
"%s services with 'depends_on' cannot be extended" % error_prefix)


def validate_service(service_config, service_names, config_file):
def validate_service(service_config, service_names, config_file, skipped_sections=[]):
service_dict, service_name = service_config.config, service_config.name
validate_service_constraints(service_dict, service_name, config_file)
validate_paths(service_dict)
validate_paths(service_dict, skipped_sections)

validate_cpu(service_config)
validate_ulimits(service_config)
Expand All @@ -708,7 +722,7 @@ def validate_service(service_config, service_names, config_file):
.format(name=service_name))


def process_service(service_config):
def process_service(service_config, skipped_sections=[]):
working_dir = service_config.working_dir
service_dict = dict(service_config.config)

Expand All @@ -718,7 +732,7 @@ def process_service(service_config):
for path in to_list(service_dict['env_file'])
]

if 'build' in service_dict:
if 'build' in service_dict and 'build' not in skipped_sections:
process_build_section(service_dict, working_dir)

if 'volumes' in service_dict and service_dict.get('volume_driver') is None:
Expand Down Expand Up @@ -1318,8 +1332,8 @@ def is_url(build_path):
return build_path.startswith(DOCKER_VALID_URL_PREFIXES)


def validate_paths(service_dict):
if 'build' in service_dict:
def validate_paths(service_dict, skipped_sections=[]):
if 'build' in service_dict and 'build' not in skipped_sections:
build = service_dict.get('build', {})

if isinstance(build, six.string_types):
Expand Down
29 changes: 29 additions & 0 deletions tests/unit/config/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,23 @@ def secret_sort(secrets):

class ConfigTest(unittest.TestCase):

def test_filter_sections(self):
filtered_sections = config.filter_sections(
"services",
[
'secrets.build',
'services',
'services.image',
'services.build',
'networks.driver',
]
)

assert filtered_sections == [
'image',
'build',
]

def test_load(self):
service_dicts = config.load(
build_config_details(
Expand Down Expand Up @@ -4575,6 +4592,18 @@ def test_nonexistent_path(self):
)
)

def test_skip_nonexistent_path(self):
service_dict = config.load(
build_config_details(
{
'foo': {'build': 'nonexistent.path'},
},
'working_dir',
'filename.yml'
), skipped_sections=['services.build']
).services
assert service_dict[0]['name'] == 'foo'

def test_relative_path(self):
relative_build_path = '../build-ctx/'
service_dict = make_service_dict(
Expand Down

0 comments on commit d2e4ba7

Please sign in to comment.