This is an automated email from the ASF dual-hosted git repository.

asorokoumov pushed a commit to branch fix-config-file
in repository https://gitbox.apache.org/repos/asf/otava.git

commit 456f83c0cc372680e003f1c2faed4164c813b6e7
Author: Alex Sorokoumov <[email protected]>
AuthorDate: Tue Mar 10 20:09:36 2026 -0700

    Fix --config-file parser broken by configargparse 1.7.3
    
    configargparse 1.7.3 changed how env var args are inserted into the arg
    list, causing `OTAVA_CONFIG` env var expansion to land after the
    subcommand positional arg. The subparser then rejects `--config-file`
    as unrecognized.
    
    The fix is to add `--config-file` to the parent subparser.
---
 otava/config.py        |  8 ++++++
 otava/main.py          | 18 +++++++------
 tests/cli_help_test.py | 70 ++++++++++++++++++++++++++++++++------------------
 3 files changed, 63 insertions(+), 33 deletions(-)

diff --git a/otava/config.py b/otava/config.py
index 126fe0e..d9cd986 100644
--- a/otava/config.py
+++ b/otava/config.py
@@ -182,6 +182,14 @@ def add_service_option_groups(parser) -> None:
     BigQueryConfig.add_parser_args(parser.add_argument_group('BigQuery 
Options', 'Options for BigQuery configuration'))
 
 
+def create_subparser_parent() -> configargparse.ArgumentParser:
+    """Create a parent parser for subparsers that accepts --config-file and 
service options."""
+    parent = configargparse.ArgumentParser(add_help=False)
+    parent.add_argument('--config-file', help='Otava config file path', 
env_var="OTAVA_CONFIG")
+    add_service_option_groups(parent)
+    return parent
+
+
 def create_config_parser() -> configargparse.ArgumentParser:
     parser = configargparse.ArgumentParser(
         add_help=False,
diff --git a/otava/main.py b/otava/main.py
index a017123..8748ae2 100644
--- a/otava/main.py
+++ b/otava/main.py
@@ -457,33 +457,35 @@ def create_otava_cli_parser() -> argparse.ArgumentParser:
         allow_abbrev=False,  # required for correct parsing of nested values 
from config file
     )
 
+    subparser_parent = config.create_subparser_parent()
+
     subparsers = parser.add_subparsers(dest="command")
     list_tests_parser = subparsers.add_parser(
         "list-tests",
         help="list available tests",
+        parents=[subparser_parent],
     )
-    config.add_service_option_groups(list_tests_parser)
     list_tests_parser.add_argument("group", help="name of the group of the 
tests", nargs="*")
 
     list_metrics_parser = subparsers.add_parser(
         "list-metrics",
         help="list available metrics for a test",
+        parents=[subparser_parent],
     )
-    config.add_service_option_groups(list_metrics_parser)
     list_metrics_parser.add_argument("test", help="name of the test")
 
-    list_groups_parser = subparsers.add_parser(
+    subparsers.add_parser(
         "list-groups",
         help="list available groups of tests",
+        parents=[subparser_parent],
     )
-    config.add_service_option_groups(list_groups_parser)
 
     analyze_parser = subparsers.add_parser(
         "analyze",
         help="analyze performance test results",
+        parents=[subparser_parent],
     )
     analyze_parser.add_argument("tests", help="name of the test or group of 
the tests", nargs="+")
-    config.add_service_option_groups(analyze_parser)
     analyze_parser.add_argument(
         "--update-grafana",
         help="Update Grafana dashboards with appropriate annotations of change 
points",
@@ -523,8 +525,8 @@ def create_otava_cli_parser() -> argparse.ArgumentParser:
 
     remove_annotations_parser = subparsers.add_parser(
         "remove-annotations",
+        parents=[subparser_parent],
     )
-    config.add_service_option_groups(remove_annotations_parser)
     remove_annotations_parser.add_argument(
         "tests", help="name of the test or test group", nargs="*"
     )
@@ -532,11 +534,11 @@ def create_otava_cli_parser() -> argparse.ArgumentParser:
         "--force", help="don't ask questions, just do it", dest="force", 
action="store_true"
     )
 
-    validate_parser = subparsers.add_parser(
+    subparsers.add_parser(
         "validate",
         help="validates the tests and metrics defined in the configuration",
+        parents=[subparser_parent],
     )
-    config.add_service_option_groups(validate_parser)
 
     return parser
 
diff --git a/tests/cli_help_test.py b/tests/cli_help_test.py
index c89724a..ad4dddd 100644
--- a/tests/cli_help_test.py
+++ b/tests/cli_help_test.py
@@ -136,9 +136,10 @@ def test_otava_analyze_help_output():
     # Python 3.13+ formats usage lines and option aliases differently
     if IS_PYTHON_313_PLUS:
         usage_and_options = """\
-usage: otava analyze [-h] [--graphite-url GRAPHITE_URL] [--grafana-url 
GRAFANA_URL]
-                     [--grafana-user GRAFANA_USER] [--grafana-password 
GRAFANA_PASSWORD]
-                     [--slack-token SLACK_TOKEN] [--postgres-hostname 
POSTGRES_HOSTNAME]
+usage: otava analyze [-h] [--config-file CONFIG_FILE] [--graphite-url 
GRAPHITE_URL]
+                     [--grafana-url GRAFANA_URL] [--grafana-user GRAFANA_USER]
+                     [--grafana-password GRAFANA_PASSWORD] [--slack-token 
SLACK_TOKEN]
+                     [--postgres-hostname POSTGRES_HOSTNAME]
                      [--postgres-port POSTGRES_PORT] [--postgres-username 
POSTGRES_USERNAME]
                      [--postgres-password POSTGRES_PASSWORD]
                      [--postgres-database POSTGRES_DATABASE]
@@ -159,6 +160,8 @@ positional arguments:
 
 options:
   -h, --help            show this help message and exit
+  --config-file CONFIG_FILE
+                        Otava config file path [env var: OTAVA_CONFIG]
   --update-grafana      Update Grafana dashboards with appropriate annotations 
of change points
   --update-postgres     Update PostgreSQL database results with change points
   --update-bigquery     Update BigQuery database results with change points
@@ -193,10 +196,11 @@ options:
   -M, --magnitude MAGNITUDE"""
     else:
         usage_and_options = """\
-usage: otava analyze [-h] [--graphite-url GRAPHITE_URL] [--grafana-url 
GRAFANA_URL]
-                     [--grafana-user GRAFANA_USER] [--grafana-password 
GRAFANA_PASSWORD]
-                     [--slack-token SLACK_TOKEN] [--postgres-hostname 
POSTGRES_HOSTNAME]
-                     [--postgres-port POSTGRES_PORT] [--postgres-username 
POSTGRES_USERNAME]
+usage: otava analyze [-h] [--config-file CONFIG_FILE] [--graphite-url 
GRAPHITE_URL]
+                     [--grafana-url GRAFANA_URL] [--grafana-user GRAFANA_USER]
+                     [--grafana-password GRAFANA_PASSWORD] [--slack-token 
SLACK_TOKEN]
+                     [--postgres-hostname POSTGRES_HOSTNAME] [--postgres-port 
POSTGRES_PORT]
+                     [--postgres-username POSTGRES_USERNAME]
                      [--postgres-password POSTGRES_PASSWORD]
                      [--postgres-database POSTGRES_DATABASE]
                      [--bigquery-project-id BIGQUERY_PROJECT_ID]
@@ -217,6 +221,8 @@ positional arguments:
 
 options:
   -h, --help            show this help message and exit
+  --config-file CONFIG_FILE
+                        Otava config file path [env var: OTAVA_CONFIG]
   --update-grafana      Update Grafana dashboards with appropriate annotations 
of change points
   --update-postgres     Update PostgreSQL database results with change points
   --update-bigquery     Update BigQuery database results with change points
@@ -324,10 +330,11 @@ def test_otava_list_tests_help_output():
     assert (
         result.stdout
         == """\
-usage: otava list-tests [-h] [--graphite-url GRAPHITE_URL] [--grafana-url 
GRAFANA_URL]
-                        [--grafana-user GRAFANA_USER] [--grafana-password 
GRAFANA_PASSWORD]
-                        [--slack-token SLACK_TOKEN] [--postgres-hostname 
POSTGRES_HOSTNAME]
-                        [--postgres-port POSTGRES_PORT] [--postgres-username 
POSTGRES_USERNAME]
+usage: otava list-tests [-h] [--config-file CONFIG_FILE] [--graphite-url 
GRAPHITE_URL]
+                        [--grafana-url GRAFANA_URL] [--grafana-user 
GRAFANA_USER]
+                        [--grafana-password GRAFANA_PASSWORD] [--slack-token 
SLACK_TOKEN]
+                        [--postgres-hostname POSTGRES_HOSTNAME] 
[--postgres-port POSTGRES_PORT]
+                        [--postgres-username POSTGRES_USERNAME]
                         [--postgres-password POSTGRES_PASSWORD]
                         [--postgres-database POSTGRES_DATABASE]
                         [--bigquery-project-id BIGQUERY_PROJECT_ID]
@@ -340,6 +347,8 @@ positional arguments:
 
 options:
   -h, --help            show this help message and exit
+  --config-file CONFIG_FILE
+                        Otava config file path [env var: OTAVA_CONFIG]
 
 Graphite Options:
   Options for Graphite configuration
@@ -401,10 +410,11 @@ def test_otava_list_metrics_help_output():
     assert (
         result.stdout
         == """\
-usage: otava list-metrics [-h] [--graphite-url GRAPHITE_URL] [--grafana-url 
GRAFANA_URL]
-                          [--grafana-user GRAFANA_USER] [--grafana-password 
GRAFANA_PASSWORD]
-                          [--slack-token SLACK_TOKEN] [--postgres-hostname 
POSTGRES_HOSTNAME]
-                          [--postgres-port POSTGRES_PORT] [--postgres-username 
POSTGRES_USERNAME]
+usage: otava list-metrics [-h] [--config-file CONFIG_FILE] [--graphite-url 
GRAPHITE_URL]
+                          [--grafana-url GRAFANA_URL] [--grafana-user 
GRAFANA_USER]
+                          [--grafana-password GRAFANA_PASSWORD] [--slack-token 
SLACK_TOKEN]
+                          [--postgres-hostname POSTGRES_HOSTNAME] 
[--postgres-port POSTGRES_PORT]
+                          [--postgres-username POSTGRES_USERNAME]
                           [--postgres-password POSTGRES_PASSWORD]
                           [--postgres-database POSTGRES_DATABASE]
                           [--bigquery-project-id BIGQUERY_PROJECT_ID]
@@ -417,6 +427,8 @@ positional arguments:
 
 options:
   -h, --help            show this help message and exit
+  --config-file CONFIG_FILE
+                        Otava config file path [env var: OTAVA_CONFIG]
 
 Graphite Options:
   Options for Graphite configuration
@@ -479,10 +491,11 @@ def test_otava_list_groups_help_output():
     assert (
         result.stdout
         == """\
-usage: otava list-groups [-h] [--graphite-url GRAPHITE_URL] [--grafana-url 
GRAFANA_URL]
-                         [--grafana-user GRAFANA_USER] [--grafana-password 
GRAFANA_PASSWORD]
-                         [--slack-token SLACK_TOKEN] [--postgres-hostname 
POSTGRES_HOSTNAME]
-                         [--postgres-port POSTGRES_PORT] [--postgres-username 
POSTGRES_USERNAME]
+usage: otava list-groups [-h] [--config-file CONFIG_FILE] [--graphite-url 
GRAPHITE_URL]
+                         [--grafana-url GRAFANA_URL] [--grafana-user 
GRAFANA_USER]
+                         [--grafana-password GRAFANA_PASSWORD] [--slack-token 
SLACK_TOKEN]
+                         [--postgres-hostname POSTGRES_HOSTNAME] 
[--postgres-port POSTGRES_PORT]
+                         [--postgres-username POSTGRES_USERNAME]
                          [--postgres-password POSTGRES_PASSWORD]
                          [--postgres-database POSTGRES_DATABASE]
                          [--bigquery-project-id BIGQUERY_PROJECT_ID]
@@ -491,6 +504,8 @@ usage: otava list-groups [-h] [--graphite-url GRAPHITE_URL] 
[--grafana-url GRAFA
 
 options:
   -h, --help            show this help message and exit
+  --config-file CONFIG_FILE
+                        Otava config file path [env var: OTAVA_CONFIG]
 
 Graphite Options:
   Options for Graphite configuration
@@ -552,8 +567,8 @@ def test_otava_remove_annotations_help_output():
     assert (
         result.stdout
         == """\
-usage: otava remove-annotations [-h] [--graphite-url GRAPHITE_URL] 
[--grafana-url GRAFANA_URL]
-                                [--grafana-user GRAFANA_USER]
+usage: otava remove-annotations [-h] [--config-file CONFIG_FILE] 
[--graphite-url GRAPHITE_URL]
+                                [--grafana-url GRAFANA_URL] [--grafana-user 
GRAFANA_USER]
                                 [--grafana-password GRAFANA_PASSWORD] 
[--slack-token SLACK_TOKEN]
                                 [--postgres-hostname POSTGRES_HOSTNAME]
                                 [--postgres-port POSTGRES_PORT]
@@ -570,6 +585,8 @@ positional arguments:
 
 options:
   -h, --help            show this help message and exit
+  --config-file CONFIG_FILE
+                        Otava config file path [env var: OTAVA_CONFIG]
   --force               don't ask questions, just do it
 
 Graphite Options:
@@ -632,10 +649,11 @@ def test_otava_validate_help_output():
     assert (
         result.stdout
         == """\
-usage: otava validate [-h] [--graphite-url GRAPHITE_URL] [--grafana-url 
GRAFANA_URL]
-                      [--grafana-user GRAFANA_USER] [--grafana-password 
GRAFANA_PASSWORD]
-                      [--slack-token SLACK_TOKEN] [--postgres-hostname 
POSTGRES_HOSTNAME]
-                      [--postgres-port POSTGRES_PORT] [--postgres-username 
POSTGRES_USERNAME]
+usage: otava validate [-h] [--config-file CONFIG_FILE] [--graphite-url 
GRAPHITE_URL]
+                      [--grafana-url GRAFANA_URL] [--grafana-user GRAFANA_USER]
+                      [--grafana-password GRAFANA_PASSWORD] [--slack-token 
SLACK_TOKEN]
+                      [--postgres-hostname POSTGRES_HOSTNAME] [--postgres-port 
POSTGRES_PORT]
+                      [--postgres-username POSTGRES_USERNAME]
                       [--postgres-password POSTGRES_PASSWORD]
                       [--postgres-database POSTGRES_DATABASE]
                       [--bigquery-project-id BIGQUERY_PROJECT_ID]
@@ -644,6 +662,8 @@ usage: otava validate [-h] [--graphite-url GRAPHITE_URL] 
[--grafana-url GRAFANA_
 
 options:
   -h, --help            show this help message and exit
+  --config-file CONFIG_FILE
+                        Otava config file path [env var: OTAVA_CONFIG]
 
 Graphite Options:
   Options for Graphite configuration

Reply via email to