diff --git a/dbt/main.py b/dbt/main.py index 8f7c7c892c1..0890e64a61c 100644 --- a/dbt/main.py +++ b/dbt/main.py @@ -295,6 +295,16 @@ def parse_args(args): help='Which target to load for the given profile' ) + base_subparser.add_argument( + '--vars', + type=str, + default='{}', + help=""" + Supply variables to the project. This argument overrides + variables defined in your dbt_project.yml file. This argument + should be a YAML string, eg. '{my_variable: my_value}'""" + ) + sub = subs.add_parser('init', parents=[base_subparser]) sub.add_argument('project_name', type=str, help='Name of the new project') sub.set_defaults(cls=init_task.InitTask, which='init') diff --git a/dbt/project.py b/dbt/project.py index 1f97ddd689a..bdb1f811076 100644 --- a/dbt/project.py +++ b/dbt/project.py @@ -87,6 +87,12 @@ def __init__(self, cfg, profiles, profiles_dir, profile_to_load=None, "Could not find profile named '{}'" .format(self.profile_to_load), self) + global_vars = dbt.utils.parse_cli_vars(getattr(args, 'vars', '{}')) + if 'vars' not in self.cfg['models']: + self.cfg['models']['vars'] = {} + + self.cfg['models']['vars'].update(global_vars) + def __str__(self): return pprint.pformat({'project': self.cfg, 'profiles': self.profiles}) diff --git a/dbt/utils.py b/dbt/utils.py index 7830b6b337b..c0008b95e5a 100644 --- a/dbt/utils.py +++ b/dbt/utils.py @@ -9,6 +9,7 @@ from dbt.compat import basestring from dbt.logger import GLOBAL_LOGGER as logger from dbt.node_types import NodeType +from dbt.clients import yaml_helper DBTConfigKeys = [ @@ -375,3 +376,20 @@ def invalid_ref_fail_unless_test(node, target_model_name, node, target_model_name, target_model_package) + + +def parse_cli_vars(var_string): + try: + cli_vars = yaml_helper.load_yaml_text(var_string) + var_type = type(cli_vars) + if var_type == dict: + return cli_vars + else: + type_name = var_type.__name__ + dbt.exceptions.raise_compiler_error( + "The --vars argument must be a YAML dictionary, but was " + "of type '{}'".format(type_name)) + except dbt.exceptions.ValidationException as e: + logger.error( + "The YAML provided in the --vars argument is not valid.\n") + raise diff --git a/test/integration/028_cli_vars/models_complex/complex_model.sql b/test/integration/028_cli_vars/models_complex/complex_model.sql new file mode 100644 index 00000000000..1022c648100 --- /dev/null +++ b/test/integration/028_cli_vars/models_complex/complex_model.sql @@ -0,0 +1,6 @@ + +select + '{{ var("variable_1") }}'::varchar as var_1, + '{{ var("variable_2")[0] }}'::varchar as var_2, + '{{ var("variable_3")["value"] }}'::varchar as var_3 + diff --git a/test/integration/028_cli_vars/models_complex/schema.yml b/test/integration/028_cli_vars/models_complex/schema.yml new file mode 100644 index 00000000000..1b9f3156167 --- /dev/null +++ b/test/integration/028_cli_vars/models_complex/schema.yml @@ -0,0 +1,7 @@ + +complex_model: + constraints: + accepted_values: + - {field: var_1, values: ["abc"]} + - {field: var_2, values: ["def"]} + - {field: var_3, values: ["jkl"]} diff --git a/test/integration/028_cli_vars/models_simple/schema.yml b/test/integration/028_cli_vars/models_simple/schema.yml new file mode 100644 index 00000000000..98e80979a55 --- /dev/null +++ b/test/integration/028_cli_vars/models_simple/schema.yml @@ -0,0 +1,5 @@ + +simple_model: + constraints: + accepted_values: + - {field: simple, values: ["abc"]} diff --git a/test/integration/028_cli_vars/models_simple/simple_model.sql b/test/integration/028_cli_vars/models_simple/simple_model.sql new file mode 100644 index 00000000000..084bd57012e --- /dev/null +++ b/test/integration/028_cli_vars/models_simple/simple_model.sql @@ -0,0 +1,4 @@ + +select + '{{ var("simple") }}'::varchar as simple + diff --git a/test/integration/028_cli_vars/test_cli_vars.py b/test/integration/028_cli_vars/test_cli_vars.py new file mode 100644 index 00000000000..347a20e4dac --- /dev/null +++ b/test/integration/028_cli_vars/test_cli_vars.py @@ -0,0 +1,54 @@ +from nose.plugins.attrib import attr +from test.integration.base import DBTIntegrationTest +import yaml + + +class TestCLIVars(DBTIntegrationTest): + @property + def schema(self): + return "cli_vars_028" + + @property + def models(self): + return "test/integration/028_cli_vars/models_complex" + + @attr(type='postgres') + def test__cli_vars_longform(self): + self.use_default_project() + self.use_profile('postgres') + + cli_vars = { + "variable_1": "abc", + "variable_2": ["def", "ghi"], + "variable_3": { + "value": "jkl" + } + } + self.run_dbt(["run", "--vars", yaml.dump(cli_vars)]) + self.run_dbt(["test"]) + + +class TestCLIVarsSimple(DBTIntegrationTest): + @property + def schema(self): + return "cli_vars_028" + + @property + def models(self): + return "test/integration/028_cli_vars/models_simple" + + @attr(type='postgres') + def test__cli_vars_shorthand(self): + self.use_default_project() + self.use_profile('postgres') + + self.run_dbt(["run", "--vars", "simple: abc"]) + self.run_dbt(["test"]) + + @attr(type='postgres') + def test__cli_vars_longer(self): + self.use_default_project() + self.use_profile('postgres') + + self.run_dbt(["run", "--vars", "{simple: abc, unused: def}"]) + self.run_dbt(["test"])