From f4de3c738767b23fce0529d9614eca5bdb5341e4 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 23 Dec 2020 11:12:56 -0500 Subject: [PATCH] Support Environment Variables in config file Environment variables can be assigned as values in the configuration file using the !ENV tag. Resolves #1954. The behavior is defined in the third-party package pyyaml_env_tag: https://github.com/waylan/pyyaml-env-tag --- docs/about/release-notes.md | 16 ++++++++++++- docs/user-guide/configuration.md | 37 +++++++++++++++++++++++++++++++ mkdocs/tests/utils/utils_tests.py | 22 ++++++++++++++++++ mkdocs/utils/__init__.py | 5 +++++ requirements/project-min.txt | 3 ++- requirements/project.txt | 3 ++- setup.py | 3 ++- 7 files changed, 85 insertions(+), 4 deletions(-) diff --git a/docs/about/release-notes.md b/docs/about/release-notes.md index 25c91c9d..fa20dff0 100644 --- a/docs/about/release-notes.md +++ b/docs/about/release-notes.md @@ -25,6 +25,20 @@ The current and past members of the MkDocs team. ### Major Additions to Version 1.2 +#### Support added for Environment Variables in the configuration file (#1954) + +Environments variables may now be specified in the configuration file with the +`!ENV` tag. The value of the variable will be parsed by the YAML parser and +converted to the appropriate type. + +```yaml +somekey: !ENV VAR_NAME +otherkey: !ENV [VAR_NAME, FALLBACK_VAR, 'default value'] +``` + +See [Environment Variables](../user-guide/configuration.md#environment-variables) +in the Configuration documentation for details. + #### A `--wait` flag has been added to the `serve` command (#2061) To delay a rebuild of the site when using the livereload server, use the @@ -34,7 +48,7 @@ To delay a rebuild of the site when using the livereload server, use the mkdocs serve --wait 60 ``` -#### Update `gh-deloy` command (#2170) +#### Update `gh-deploy` command (#2170) The vendored (and modified) copy of ghp_import has been replaced with a dependency on the upstream library. As of version 1.0.0, [ghp_import] includes a diff --git a/docs/user-guide/configuration.md b/docs/user-guide/configuration.md index 6087fd0b..a36454f6 100644 --- a/docs/user-guide/configuration.md +++ b/docs/user-guide/configuration.md @@ -12,6 +12,43 @@ project directory named `mkdocs.yml`. As a minimum, this configuration file must contain the `site_name` setting. All other settings are optional. +### Environment Variables + +In most cases, the value of a configuration option is set directly in the +configuration file. However, as an option, the value of a configuration option +may be set to the value of an environment variable using the `!ENV` tag. For +example, to set the value of the `site_name` option to the value of the +variable `SITE_NAME` the YAML file may contain the following: + +```yaml +site_name: !ENV SITE_NAME +``` + +If the environment variable is not defined, then the configuration setting +would be assigned a `null` (or `None` in Python) value. A default value can be +defined as the last value in a list. Like this: + +```yaml +site_name: !ENV [SITE_NAME, 'My default site name'] +``` + +Multiple fallback variables can be used as well. Note that the last value is +not an environment variable, but must be a value to use as a default if none +of the specified environment variables are defined. + +```yaml +site_name: !ENV [SITE_NAME, OTHER_NAME, 'My default site name'] +``` + +Simple types defined within an environment variable such as string, bool, +integer, float, datestamp and null are parsed as if they were defined directly +in the YAML file, which means that the value will be converted to the +appropriate type. However, complex types such as lists and key/value pairs +cannot be defined within a single environment variable. + +For more details, see the [pyyaml_env_tag](https://github.com/waylan/pyyaml-env-tag) +project. + ## Project information ### site_name diff --git a/mkdocs/tests/utils/utils_tests.py b/mkdocs/tests/utils/utils_tests.py index 609b9f00..01c9ea8a 100644 --- a/mkdocs/tests/utils/utils_tests.py +++ b/mkdocs/tests/utils/utils_tests.py @@ -305,6 +305,28 @@ class UtilsTests(unittest.TestCase): self.assertTrue(isinstance(config['key'], str)) self.assertTrue(isinstance(config['key2'][0], str)) + @mock.patch.dict(os.environ, {'VARNAME': 'Hello, World!', 'BOOLVAR': 'false'}) + def test_env_var_in_yaml(self): + + yaml_src = dedent( + ''' + key1: !ENV VARNAME + key2: !ENV UNDEFINED + key3: !ENV [UNDEFINED, default] + key4: !ENV [UNDEFINED, VARNAME, default] + key5: !ENV BOOLVAR + ''' + ) + config = utils.yaml_load(yaml_src) + self.assertIsInstance(config['key1'], str) + self.assertEqual(config['key1'], 'Hello, World!') + self.assertIsNone(config['key2']) + self.assertIsInstance(config['key3'], str) + self.assertEqual(config['key3'], 'default') + self.assertIsInstance(config['key4'], str) + self.assertEqual(config['key4'], 'Hello, World!') + self.assertIs(config['key5'], False) + def test_copy_files(self): src_paths = [ 'foo.txt', diff --git a/mkdocs/utils/__init__.py b/mkdocs/utils/__init__.py index 9844de48..221e6b2e 100644 --- a/mkdocs/utils/__init__.py +++ b/mkdocs/utils/__init__.py @@ -17,6 +17,7 @@ import posixpath import functools from datetime import datetime, timezone from urllib.parse import urlparse +from yaml_env_tag import construct_env_tag from mkdocs import exceptions @@ -56,6 +57,10 @@ def yaml_load(source, loader=yaml.Loader): # will be unicode on translation. Loader.add_constructor('tag:yaml.org,2002:str', construct_yaml_str) + # Attach Environment Variable constructor. + # See https://github.com/waylan/pyyaml-env-tag + Loader.add_constructor('!ENV', construct_env_tag) + try: return yaml.load(source, Loader) finally: diff --git a/requirements/project-min.txt b/requirements/project-min.txt index a25e6602..a66cbdc2 100644 --- a/requirements/project-min.txt +++ b/requirements/project-min.txt @@ -5,4 +5,5 @@ Markdown==3.2.1 PyYAML==5.1 tornado==4.1 mdx_gh_links==0.2 -ghp-import==1.0 \ No newline at end of file +ghp-import==1.0 +pyyaml_env_tag==0.1 diff --git a/requirements/project.txt b/requirements/project.txt index a7c284ac..3b3201f9 100644 --- a/requirements/project.txt +++ b/requirements/project.txt @@ -5,4 +5,5 @@ Markdown>=3.2.1 PyYAML>=5.2 tornado>=5.1.1 mdx_gh_links>=0.2 -ghp-import>=1.0 \ No newline at end of file +ghp-import>=1.0 +pyyaml_env_tag>=0.1 diff --git a/setup.py b/setup.py index 2595c61d..7640b473 100755 --- a/setup.py +++ b/setup.py @@ -61,7 +61,8 @@ setup( 'Markdown>=3.2.1', 'PyYAML>=3.10', 'tornado>=5.0', - 'ghp-import>=1.0' + 'ghp-import>=1.0', + 'pyyaml_env_tag>=0.1' ], python_requires='>=3.6', entry_points={