As part of automating my release handling, I’ve been fiddling with ways of pushing the git tag into the version used in mix.exs and wondered if anybody else has come up with a better / nicer way:
defmodule Foo.MixProject do
use Mix.Project
def project() do
[version: set_version(),
...]
end
# stash the tag so that it's rolled into the next commit and therefore
# available in hex packages when git tag info may not be present
# alternatively we *could* abuse hex_metadata.config for that?
defp set_version() do
v = get_version()
File.write!(".version", v)
v
end
defp get_version() do
# get version from closest git tag, last saved tag, or assume 0.0.0-alpha
get_version(File.read(".version"), File.dir?(".git"), System.find_executable("git"))
|> String.replace_prefix("v", "")
|> String.trim_trailing()
end
# fallback when there is no actual error, just missing information
defp get_version(:missing), do: "0.0.0-alpha"
# no .version file, must be first run: assume lowest possible version
defp get_version({:error, _}, _, _), do: get_version(:missing)
# .version exists, but no .git dir, probably inside hex package
defp get_version({:ok, v}, false, _), do: v
# .version exists, and we can read git tags
defp get_version({:ok, _}, true, git) when is_binary(git) do
case System.cmd("git", ~w[describe --dirty --abbrev=0 --tags --first-parent],
stderr_to_stdout: true
) do
{v, 0} -> v
_ -> get_version(:missing)
end
end
# something is very wrong so we give up and hex publishing will fail
defp get_version(_, _, _), do: "unknown"