Repository: spack/spack

Issue:
Determining Spack Version
@scheibelp @tgamblin 

I saw this on the telcon notes:

> Determining Spack version
> 
> git log will tell you the commits (including the latest commit hash and date)
> This requires pulling git with git clone (and make sure you get the develop branch vs. master)
> If you use the download option at github, this will strip git's data and git log won't work
> 

Maybe we could use one of these:

https://github.com/warner/python-versioneer
https://github.com/manuelbua/gitver
#7937 



Discussion:

Resolving patch:
diff --git a/lib/spack/spack/main.py b/lib/spack/spack/main.py
--- a/lib/spack/spack/main.py
+++ b/lib/spack/spack/main.py
@@ -13,6 +13,7 @@
 import sys
 import re
 import os
+import os.path
 import inspect
 import pstats
 import argparse
@@ -35,6 +36,7 @@
 import spack.store
 import spack.util.debug
 import spack.util.path
+import spack.util.executable as exe
 from spack.error import SpackError
 
 
@@ -107,6 +109,34 @@ def add_all_commands(parser):
         parser.add_command(cmd)
 
 
+def get_version():
+    """Get a descriptive version of this instance of Spack.
+
+    If this is a git repository, and if it is not on a release tag,
+    return a string like:
+
+        release_version-commits_since_release-commit
+
+    If we *are* at a release tag, or if this is not a git repo, return
+    the real spack release number (e.g., 0.13.3).
+
+    """
+    git_path = os.path.join(spack.paths.prefix, ".git")
+    if os.path.exists(git_path):
+        git = exe.which("git")
+        if git:
+            desc = git("-C", spack.paths.prefix, "describe", "--tags",
+                       output=str, fail_on_error=False)
+
+            if git.returncode == 0:
+                match = re.match(r"v([^-]+)-([^-]+)-g([a-f\d]+)", desc)
+                if match:
+                    v, n, commit = match.groups()
+                    return "%s-%s-%s" % (v, n, commit)
+
+    return spack.spack_version
+
+
 def index_commands():
     """create an index of commands by section for this help level"""
     index = {}
@@ -679,7 +709,7 @@ def main(argv=None):
     # -h, -H, and -V are special as they do not require a command, but
     # all the other options do nothing without a command.
     if args.version:
-        print(spack.spack_version)
+        print(get_version())
         return 0
     elif args.help:
         sys.stdout.write(parser.format_help(level=args.help))


Test patch:
diff --git a/lib/spack/spack/test/main.py b/lib/spack/spack/test/main.py
new file mode 100644
--- /dev/null
+++ b/lib/spack/spack/test/main.py
@@ -0,0 +1,63 @@
+# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os
+
+import llnl.util.filesystem as fs
+
+import spack.paths
+from spack.main import get_version, main
+
+
+def test_get_version_no_match_git(tmpdir, working_env):
+    git = str(tmpdir.join("git"))
+    with open(git, "w") as f:
+        f.write("""#!/bin/sh
+echo v0.13.3
+""")
+    fs.set_executable(git)
+
+    os.environ["PATH"] = str(tmpdir)
+    assert spack.spack_version == get_version()
+
+
+def test_get_version_match_git(tmpdir, working_env):
+    git = str(tmpdir.join("git"))
+    with open(git, "w") as f:
+        f.write("""#!/bin/sh
+echo v0.13.3-912-g3519a1762
+""")
+    fs.set_executable(git)
+
+    os.environ["PATH"] = str(tmpdir)
+    assert "0.13.3-912-3519a1762" == get_version()
+
+
+def test_get_version_no_repo(tmpdir, monkeypatch):
+    monkeypatch.setattr(spack.paths, "prefix", str(tmpdir))
+    assert spack.spack_version == get_version()
+
+
+def test_get_version_no_git(tmpdir, working_env):
+    os.environ["PATH"] = str(tmpdir)
+    assert spack.spack_version == get_version()
+
+
+def test_main_calls_get_version(tmpdir, capsys, working_env):
+    os.environ["PATH"] = str(tmpdir)
+    main(["-V"])
+    assert spack.spack_version == capsys.readouterr()[0].strip()
+
+
+def test_get_version_bad_git(tmpdir, working_env):
+    bad_git = str(tmpdir.join("git"))
+    with open(bad_git, "w") as f:
+        f.write("""#!/bin/sh
+exit 1
+""")
+    fs.set_executable(bad_git)
+
+    os.environ["PATH"] = str(tmpdir)
+    assert spack.spack_version == get_version()