Repository: spack/spack

Issue:
Using CDash reporter fails if `--log-file` is not passed explicitly
### Steps to reproduce

Reported from @zackgalbreath Possibly introduced by https://github.com/spack/spack/pull/34712

The following command:
```console
$ spack install --overwrite --log-format=cdash --cdash-upload-url=https://blahblah/submit.php?project=debugging zlib
```
fails to upload to CDash, since it tries to use the URL as a fallback name for the XML file to be generated. This command instead:
```console
$ spack install --overwrite --log-file=/tmp/cdash.xml --log-format=cdash --cdash-upload-url=https://blahblah/submit.php?project=debugging zlib
```
completes succesfully.


### Error message

```console
$ spack install --overwrite --log-format=cdash --cdash-upload-url=https://blahblah/submit.php?project=debugging zlib
[ ... ]
==> [2023-02-04-14:18:20.816413] zlib: Successfully installed zlib-1.2.13-4kpu5pp5psfmp643ejkr6itq5bskmq5l
  Stage: 0.07s.  Edit: 0.62s.  Build: 1.02s.  Install: 0.09s.  Total: 1.84s
[+] /home/culpo/PycharmProjects/spack/opt/spack/linux-ubuntu20.04-icelake/gcc-9.4.0/zlib-1.2.13-4kpu5pp5psfmp643ejkr6itq5bskmq5l
==> [2023-02-04-14:18:20.825182] Temporary directory deleted [/home/culpo/PycharmProjects/spack/opt/spack/linux-ubuntu20.04-icelake/gcc-9.4.0/.backupf3o6x6x6]
==> [2023-02-04-14:18:20.825331] Flagging zlib-1.2.13-4kpu5pp5psfmp643ejkr6itq5bskmq5l as installed
==> [2023-02-04-14:18:20.825438] Downgrading to a read lock on zlib-1.2.13-4kpu5pp5psfmp643ejkr6itq5bskmq5l with timeout 1.000ns
==> [2023-02-04-14:18:20.825529] zlib-1.2.13-4kpu5pp5psfmp643ejkr6itq5bskmq5l is now read locked
==> [2023-02-04-14:18:20.825568] Releasing read lock on zlib-1.2.13-4kpu5pp5psfmp643ejkr6itq5bskmq5l
Traceback (most recent call last):
  File "/home/culpo/PycharmProjects/spack/bin/spack", line 54, in <module>
    sys.exit(main())
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack_installable/main.py", line 37, in main
    sys.exit(spack.main.main(argv))
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/main.py", line 1004, in main
    return _main(argv)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/main.py", line 959, in _main
    return finish_parse_and_run(parser, cmd_name, env_format_error)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/main.py", line 987, in finish_parse_and_run
    return _invoke_command(command, parser, args, unknown)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/main.py", line 636, in _invoke_command
    return_val = command(parser, args)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/cmd/install.py", line 547, in install
    install_specs(zip(abstract_specs, concrete_specs), install_kwargs, args)
  File "/usr/lib/python3.8/contextlib.py", line 120, in __exit__
    next(self.gen)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/report.py", line 253, in build_context_manager
    reporter.build_report(filename, specs=collector.specs)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/reporters/cdash.py", line 264, in build_report
    self.build_report_for_package(directory_name, package, duration)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/reporters/cdash.py", line 124, in build_report_for_package
    report_data = self.initialize_report(directory_name)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/reporters/cdash.py", line 371, in initialize_report
    os.mkdir(directory_name)
FileNotFoundError: [Errno 2] No such file or directory: 'https://blahblah/submit.php?project=debugging'
```

### Information on your system

* **Spack:** 0.20.0.dev0 (5d4c25035430227ed68c868f27c1e8bc16537dcd)
* **Python:** 3.8.10
* **Platform:** linux-ubuntu20.04-icelake
* **Concretizer:** clingo


**Additional notes**: It was also reported that `--log-format=cdash` is not inferred anymore from other options.

### General information

- [X] I have run `spack debug report` and reported the version of Spack/Python/Platform
- [X] I have searched the issues of this repo and believe this is not a duplicate
- [X] I have run the failing commands in debug mode and reported the output


Discussion:

Resolving patch:
diff --git a/lib/spack/spack/cmd/common/arguments.py b/lib/spack/spack/cmd/common/arguments.py
--- a/lib/spack/spack/cmd/common/arguments.py
+++ b/lib/spack/spack/cmd/common/arguments.py
@@ -6,6 +6,7 @@
 
 import argparse
 import os.path
+import textwrap
 
 from llnl.util.lang import stable_partition
 
@@ -415,6 +416,40 @@ def add_cdash_args(subparser, add_help):
     cdash_subgroup.add_argument("--cdash-buildstamp", default=None, help=cdash_help["buildstamp"])
 
 
+def print_cdash_help():
+    parser = argparse.ArgumentParser(
+        formatter_class=argparse.RawDescriptionHelpFormatter,
+        epilog=textwrap.dedent(
+            """\
+environment variables:
+SPACK_CDASH_AUTH_TOKEN
+                    authentication token to present to CDash
+                    """
+        ),
+    )
+    add_cdash_args(parser, True)
+    parser.print_help()
+
+
+def sanitize_reporter_options(namespace: argparse.Namespace):
+    """Sanitize options that affect generation and configuration of reports, like
+    CDash or JUnit.
+
+    Args:
+        namespace: options parsed from cli
+    """
+    has_any_cdash_option = (
+        namespace.cdash_upload_url or namespace.cdash_build or namespace.cdash_site
+    )
+    if namespace.log_format == "junit" and has_any_cdash_option:
+        raise argparse.ArgumentTypeError("cannot pass any cdash option when --log-format=junit")
+
+    # If any CDash option is passed, assume --log-format=cdash is implied
+    if namespace.log_format is None and has_any_cdash_option:
+        namespace.log_format = "cdash"
+        namespace.reporter = _cdash_reporter(namespace)
+
+
 class ConfigSetAction(argparse.Action):
     """Generic action for setting spack config options from CLI.
 
diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py
--- a/lib/spack/spack/cmd/install.py
+++ b/lib/spack/spack/cmd/install.py
@@ -7,7 +7,6 @@
 import os
 import shutil
 import sys
-import textwrap
 from typing import List
 
 import llnl.util.filesystem as fs
@@ -260,7 +259,7 @@ def default_log_file(spec):
 
 def report_filename(args: argparse.Namespace, specs: List[spack.spec.Spec]) -> str:
     """Return the filename to be used for reporting to JUnit or CDash format."""
-    result = args.log_file or args.cdash_upload_url or default_log_file(specs[0])
+    result = args.log_file or default_log_file(specs[0])
     return result
 
 
@@ -348,21 +347,6 @@ def install_specs_outside_environment(specs, install_kwargs):
     builder.install()
 
 
-def print_cdash_help():
-    parser = argparse.ArgumentParser(
-        formatter_class=argparse.RawDescriptionHelpFormatter,
-        epilog=textwrap.dedent(
-            """\
-environment variables:
-SPACK_CDASH_AUTH_TOKEN
-                    authentication token to present to CDash
-                    """
-        ),
-    )
-    arguments.add_cdash_args(parser, True)
-    parser.print_help()
-
-
 def install_all_specs_from_active_environment(
     install_kwargs, only_concrete, cli_test_arg, reporter_factory
 ):
@@ -496,7 +480,7 @@ def install(parser, args):
     tty.set_verbose(args.verbose or args.install_verbose)
 
     if args.help_cdash:
-        print_cdash_help()
+        spack.cmd.common.arguments.print_cdash_help()
         return
 
     if args.no_checksum:
@@ -505,6 +489,8 @@ def install(parser, args):
     if args.deprecated:
         spack.config.set("config:deprecated", True, scope="command_line")
 
+    spack.cmd.common.arguments.sanitize_reporter_options(args)
+
     def reporter_factory(specs):
         if args.log_format is None:
             return None


Test patch:
diff --git a/lib/spack/spack/cmd/test.py b/lib/spack/spack/cmd/test.py
--- a/lib/spack/spack/cmd/test.py
+++ b/lib/spack/spack/cmd/test.py
@@ -11,7 +11,6 @@
 import re
 import shutil
 import sys
-import textwrap
 
 from llnl.util import lang, tty
 from llnl.util.tty import colify
@@ -171,20 +170,11 @@ def test_run(args):
 
     # cdash help option
     if args.help_cdash:
-        parser = argparse.ArgumentParser(
-            formatter_class=argparse.RawDescriptionHelpFormatter,
-            epilog=textwrap.dedent(
-                """\
-environment variables:
-  SPACK_CDASH_AUTH_TOKEN
-                        authentication token to present to CDash
-                        """
-            ),
-        )
-        arguments.add_cdash_args(parser, True)
-        parser.print_help()
+        arguments.print_cdash_help()
         return
 
+    arguments.sanitize_reporter_options(args)
+
     # set config option for fail-fast
     if args.fail_fast:
         spack.config.set("config:fail_fast", True, scope="command_line")
diff --git a/lib/spack/spack/test/cmd/install.py b/lib/spack/spack/test/cmd/install.py
--- a/lib/spack/spack/test/cmd/install.py
+++ b/lib/spack/spack/test/cmd/install.py
@@ -1187,3 +1187,16 @@ def test_padded_install_runtests_root(install_mockery_mutable_config, mock_fetch
     spack.config.set("config:install_tree:padded_length", 255)
     output = install("--test=root", "--no-cache", "test-build-callbacks", fail_on_error=False)
     assert output.count("method not implemented") == 1
+
+
+@pytest.mark.regression("35337")
+def test_report_filename_for_cdash(install_mockery_mutable_config, mock_fetch):
+    """Test that the temporary file used to write the XML for CDash is not the upload URL"""
+    parser = argparse.ArgumentParser()
+    spack.cmd.install.setup_parser(parser)
+    args = parser.parse_args(
+        ["--cdash-upload-url", "https://blahblah/submit.php?project=debugging", "a"]
+    )
+    _, specs = spack.cmd.install.specs_from_cli(args, {})
+    filename = spack.cmd.install.report_filename(args, specs)
+    assert filename != "https://blahblah/submit.php?project=debugging"