feat(build runner): added in context, dockerfile_location

this is a new feature meant to allow people to use any file as
  a dockerfile and any folder as a context directory
This commit is contained in:
Charlton Austin 2017-03-21 17:24:11 -04:00
parent 90b130fe16
commit e6d201e0b0
29 changed files with 531 additions and 111 deletions

View file

@ -1,3 +1,4 @@
import os
from abc import ABCMeta, abstractmethod
from jsonschema import validate
from six import add_metaclass
@ -290,7 +291,7 @@ class BuildTriggerHandler(object):
def get_dockerfile_path(self):
""" Returns the normalized path to the Dockerfile found in the subdirectory
in the config. """
dockerfile_path = self.config.get('subdir') or 'Dockerfile'
dockerfile_path = self.config.get('dockerfile_path') or 'Dockerfile'
if dockerfile_path[0] == '/':
dockerfile_path = dockerfile_path[1:]
return dockerfile_path
@ -303,10 +304,11 @@ class BuildTriggerHandler(object):
ref = metadata.get('ref', None)
commit_sha = metadata['commit']
default_branch = metadata.get('default_branch', None)
prepared = PreparedBuild(self.trigger)
prepared.name_from_sha(commit_sha)
prepared.subdirectory = config.get('subdir', None)
# TODO: Charlie Tuesday, March 28, 2017 come back and clean up subdirectory.
prepared.subdirectory = config.get('dockerfile_path', None)
prepared.context = config.get('context', None)
prepared.is_manual = is_manual
prepared.metadata = metadata
@ -327,3 +329,28 @@ class BuildTriggerHandler(object):
namespaces = list(namespaces_dict.values())
validate(namespaces, NAMESPACES_SCHEMA)
return namespaces
@classmethod
def get_parent_directory_mappings(cls, dockerfile_path, current_paths=None):
""" Returns a map of dockerfile_paths to it's possible contexts. """
if dockerfile_path == "":
return {}
if dockerfile_path[0] != os.path.sep:
dockerfile_path = os.path.sep + dockerfile_path
dockerfile_path = os.path.normpath(dockerfile_path)
all_paths = set()
path, _ = os.path.split(dockerfile_path)
if path == "":
path = os.path.sep
all_paths.add(path)
for i in range(1, len(path.split(os.path.sep))):
path, _ = os.path.split(path)
all_paths.add(path)
if current_paths:
return dict({dockerfile_path: list(all_paths)}, **current_paths)
return {dockerfile_path: list(all_paths)}

View file

@ -371,17 +371,22 @@ class GithubBuildTrigger(BuildTriggerHandler):
raise RepositoryReadException(message)
path = self.get_dockerfile_path()
if not path or not self.filename_is_dockerfile(os.path.basename(path)):
if not path:
return None
try:
file_info = repo.get_file_contents(path)
except GithubException as ghe:
# TypeError is needed because directory inputs cause a TypeError
except (GithubException, TypeError) as ghe:
logger.error("got error from trying to find github file %s" % ghe)
return None
if file_info is None:
return None
if isinstance(file_info, list):
return None
content = file_info.content
if file_info.encoding == 'base64':
content = base64.b64decode(content)

View file

@ -4,11 +4,11 @@ from mock import Mock
from buildtrigger.bitbuckethandler import BitbucketBuildTrigger
from util.morecollections import AttrDict
def get_bitbucket_trigger(subdir=''):
def get_bitbucket_trigger(dockerfile_path=''):
trigger_obj = AttrDict(dict(auth_token='foobar', id='sometrigger'))
trigger = BitbucketBuildTrigger(trigger_obj, {
'build_source': 'foo/bar',
'subdir': subdir,
'dockerfile_path': dockerfile_path,
'username': 'knownuser'
})

View file

@ -6,9 +6,9 @@ from github import GithubException
from buildtrigger.githubhandler import GithubBuildTrigger
from util.morecollections import AttrDict
def get_github_trigger(subdir=''):
def get_github_trigger(dockerfile_path=''):
trigger_obj = AttrDict(dict(auth_token='foobar', id='sometrigger'))
trigger = GithubBuildTrigger(trigger_obj, {'build_source': 'foo', 'subdir': subdir})
trigger = GithubBuildTrigger(trigger_obj, {'build_source': 'foo', 'dockerfile_path': dockerfile_path})
trigger._get_client = get_mock_github
return trigger

View file

@ -4,11 +4,11 @@ from mock import Mock
from buildtrigger.gitlabhandler import GitLabBuildTrigger
from util.morecollections import AttrDict
def get_gitlab_trigger(subdir=''):
def get_gitlab_trigger(dockerfile_path=''):
trigger_obj = AttrDict(dict(auth_token='foobar', id='sometrigger'))
trigger = GitLabBuildTrigger(trigger_obj, {
'build_source': 'foo/bar',
'subdir': subdir,
'dockerfile_path': dockerfile_path,
'username': 'knownuser'
})

View file

@ -13,3 +13,43 @@ from buildtrigger.basehandler import BuildTriggerHandler
])
def test_path_is_dockerfile(input, output):
assert BuildTriggerHandler.filename_is_dockerfile(input) == output
@pytest.mark.parametrize('input,output', [
("", {}),
("/a", {"/a": ["/"]}),
("a", {"/a": ["/"]}),
("/b/a", {"/b/a": ["/b", "/"]}),
("b/a", {"/b/a": ["/b", "/"]}),
("/c/b/a", {"/c/b/a": ["/c/b", "/c", "/"]}),
("/a//b//c", {"/a/b/c": ["/", "/a", "/a/b"]}),
("/a", {"/a": ["/"]}),
])
def test_subdir_path_map_no_previous(input, output):
actual_mapping = BuildTriggerHandler.get_parent_directory_mappings(input)
for key in actual_mapping:
value = actual_mapping[key]
actual_mapping[key] = value.sort()
for key in output:
value = output[key]
output[key] = value.sort()
assert actual_mapping == output
@pytest.mark.parametrize('new_path,original_dictionary,output', [
("/a", {}, {"/a": ["/"]}),
("b", {"/a": ["some_path", "another_path"]}, {"/a": ["some_path", "another_path"], "/b": ["/"]}),
("/a/b/c/d", {"/e": ["some_path", "another_path"]},
{"/e": ["some_path", "another_path"], "/a/b/c/d": ["/", "/a", "/a/b", "/a/b/c"]}),
])
def test_subdir_path_map(new_path, original_dictionary, output):
actual_mapping = BuildTriggerHandler.get_parent_directory_mappings(new_path, original_dictionary)
for key in actual_mapping:
value = actual_mapping[key]
actual_mapping[key] = value.sort()
for key in output:
value = output[key]
output[key] = value.sort()
assert actual_mapping == output

View file

@ -16,13 +16,13 @@ def test_list_build_subdirs(bitbucket_trigger):
assert bitbucket_trigger.list_build_subdirs() == ["/Dockerfile"]
@pytest.mark.parametrize('subdir, contents', [
@pytest.mark.parametrize('dockerfile_path, contents', [
('/Dockerfile', 'hello world'),
('somesubdir/Dockerfile', 'hi universe'),
('unknownpath', None),
])
def test_load_dockerfile_contents(subdir, contents):
trigger = get_bitbucket_trigger(subdir)
def test_load_dockerfile_contents(dockerfile_path, contents):
trigger = get_bitbucket_trigger(dockerfile_path)
assert trigger.load_dockerfile_contents() == contents

View file

@ -68,13 +68,13 @@ def test_handle_trigger_request(github_trigger, payload, expected_error, expecte
assert isinstance(github_trigger.handle_trigger_request(request), PreparedBuild)
@pytest.mark.parametrize('subdir, contents', [
@pytest.mark.parametrize('dockerfile_path, contents', [
('/Dockerfile', 'hello world'),
('somesubdir/Dockerfile', 'hi universe'),
('unknownpath', None),
])
def test_load_dockerfile_contents(subdir, contents):
trigger = get_github_trigger(subdir)
def test_load_dockerfile_contents(dockerfile_path, contents):
trigger = get_github_trigger(dockerfile_path)
assert trigger.load_dockerfile_contents() == contents

View file

@ -16,13 +16,13 @@ def test_list_build_subdirs(gitlab_trigger):
assert gitlab_trigger.list_build_subdirs() == ['/Dockerfile']
@pytest.mark.parametrize('subdir, contents', [
@pytest.mark.parametrize('dockerfile_path, contents', [
('/Dockerfile', 'hello world'),
('somesubdir/Dockerfile', 'hi universe'),
('unknownpath', None),
])
def test_load_dockerfile_contents(subdir, contents):
trigger = get_gitlab_trigger(subdir)
def test_load_dockerfile_contents(dockerfile_path, contents):
trigger = get_gitlab_trigger(dockerfile_path)
assert trigger.load_dockerfile_contents() == contents