Repository: locustio/locust

Issue:
Add --config parameter
<!-- 
If you have a general question about how to use Locust, please check Stack Overflow first https://stackoverflow.com/questions/tagged/locust

You can also ask new questions on SO, https://stackoverflow.com/questions/ask just remember to tag your question with "locust".
-->

### Is your feature request related to a problem? Please describe.
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
I would like to be able to have multiple config files stored in version control for different purposes (eg one that uses step-mode and one that doesn't).

### Describe the solution you'd like
<!-- A clear and concise description of what you want to happen -->
`ConfigArgParse` makes it easy to add this capability. I think it could be done with a single line in `parse_options`:
`parser.add_argument('--config', is_config_file_arg=True, help='config file path')`

### Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered -->
Current workaround is to keep multiple sets of configurations in `locust.conf`, with the active one uncommented.


Discussion:

Patch:
diff --git a/docs/configuration.rst b/docs/configuration.rst
index a876e34a..a7f95a6c 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -27,3 +27,33 @@ Most of the configuration that can be set through command line arguments can als
 environment variables. Here's a table of all the available environment variables:
 
 .. include:: env-options.rst
+
+
+
+.. _configuration-files:
+
+Configuration files
+-------------------
+
+Any of the configuration that can be set through command line arguments can also be set by a
+configuration file in the `config file <https://github.com/bw2/ConfigArgParse#config-file-syntax>`_
+format.
+Locust will look for ``locust.conf`` or ``~/.locust.conf`` by default, or a file may be specified
+with the ``--config`` flag. Parameters passed as command line arguments will override the settings
+from the config file.
+
+
+.. code-block::
+
+    # step_mode.conf in current directory
+    locustfile locust_files/my_locust_file.py
+    host localhost
+    users 100
+    hatch-rate 10
+    step-load
+    step-users 20
+    step-time 60
+
+.. code-block:: console
+
+    $ locust --config=step_mode.conf
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
index d79f2677..2da12ff1 100644
--- a/docs/quickstart.rst
+++ b/docs/quickstart.rst
@@ -144,8 +144,10 @@ host defaults to 127.0.0.1):
     $ locust -f locust_files/my_locust_file.py --worker --master-host=192.168.0.100
 
 
-Parameters can also be set as :ref:`environment variables <environment-variables>`, or in a 
-`config file <https://github.com/bw2/ConfigArgParse#config-file-syntax>`_ (``locust.conf`` or ``~/.locust.conf``).
+Parameters can also be set as :ref:`environment variables <environment-variables>`, or in a
+`config file <https://github.com/bw2/ConfigArgParse#config-file-syntax>`_.
+Locust will look for ``locust.conf`` or ``~/.locust.conf`` by default, or a file may be specified
+with the ``--config`` flag.
 
 For example: (this will do the same thing as the previous command)
 
diff --git a/locust/argument_parser.py b/locust/argument_parser.py
index 3d0bf758..36ddd843 100644
--- a/locust/argument_parser.py
+++ b/locust/argument_parser.py
@@ -76,6 +76,8 @@ def get_empty_argument_parser(add_help=True, default_config_files=DEFAULT_CONFIG
         help="Python module file to import, e.g. '../other.py'. Default: locustfile",
         env_var="LOCUST_LOCUSTFILE",
     )
+    parser.add_argument('--config', is_config_file_arg=True, help='Config file path')
+
     return parser
 
 


Test patch:
diff --git a/locust/test/test_main.py b/locust/test/test_main.py
index 34ef2bbe..c0065686 100644
--- a/locust/test/test_main.py
+++ b/locust/test/test_main.py
@@ -77,6 +77,40 @@ class TestLoadLocustfile(LocustTestCase):
         self.assertEqual(None, env.host)
         self.assertFalse(env.reset_stats)
 
+    def test_specify_config_file(self):
+        with temporary_file(textwrap.dedent("""
+            host = localhost  # With "="
+            u 100             # Short form
+            hatch-rate 5      # long form
+            headless          # boolean
+        """), suffix=".conf") as conf_file_path:
+            options = parse_options(args=[
+                "--config", conf_file_path,
+            ])
+            self.assertEqual(conf_file_path, options.config)
+            self.assertEqual("localhost", options.host)
+            self.assertEqual(100, options.num_users)
+            self.assertEqual(5, options.hatch_rate)
+            self.assertTrue(options.headless)
+
+    def test_command_line_arguments_override_config_file(self):
+        with temporary_file("host=from_file", suffix=".conf") as conf_file_path:
+            options = parse_options(args=[
+                "--config", conf_file_path,
+                "--host", "from_args",
+            ])
+            self.assertEqual("from_args", options.host)
+
+    def test_locustfile_can_be_set_in_config_file(self):
+        with temporary_file(
+            "locustfile my_locust_file.py",
+            suffix=".conf",
+        ) as conf_file_path:
+            options = parse_options(args=[
+                "--config", conf_file_path,
+            ])
+            self.assertEqual("my_locust_file.py", options.locustfile)
+
 
 class LocustProcessIntegrationTest(TestCase):
     def setUp(self):