对 elixir 应用程序 phoenix 进行自动版本控制的最佳方法
Best approach to do auto versioning of an elixir application phoenix
我正在使用 distillery 为 phoenix 应用程序进行热代码升级。我用它来创建应用程序的版本。
def project do
{result, _exit_code} = System.cmd("git", ["rev-parse", "HEAD"])
git_sha = String.slice(result, 0, 7)
[app: :evercam_media,
version: "1.0.1-a#{git_sha}",
elixir: "~> 1.7",
elixirc_paths: elixirc_paths(Mix.env),
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
compilers: [:phoenix] ++ Mix.compilers,
aliases: aliases(),
deps: deps()]
end
这会创建版本,但该版本不适用于热代码升级并会弄乱 relup
文件。当我进行 1.0.1、1.0.2 和 1.0.3 之类的版本控制时。然后热代码部署工作正常。但是有什么办法可以让这个东西动态化吗?
我正在使用 distillery 部署到远程服务器。
更新:
我正在使用 distillery 进行部署,但自动版本无法正常工作,除非它们是 1.0.1 或 1.0.2 或 1.0.3。我试过下面的答案。以及 git describe --tags
也是如此。但酒厂只使用 2 个版本,然后每次使用过去的版本创建新版本。
git_sha
的问题是它没有排序。根据普通字母数字排序,下一个版本的编号被假定为大于前一个版本。 sha
情况并非如此。
您可以为此目的使用日期。例如
git log -1 --date=raw --format=%cd
#⇒ 1535467693 +0200 # seconds since epoch
现在让我们把它炼成:
{epoch, _} = System.cmd("git", ~w|log -1 --date=raw --format=%cd|)
[sec, tz] =
epoch
|> String.split(~r/\s+/, trim: true)
|> Enum.map(&String.to_integer/1)
#⇒ [1527769224, 200]
sec + tz * 36 # * 60 * 60 / 100
#⇒ 1527776424
上面的数字一直在增长。
旁注: 尽可能使用就地二进制模式匹配而不是 String.slice/3
:
{<<git_sha::binary-size(8), _rest::binary>>, _exit_code} =
System.cmd("git", ["rev-parse", "HEAD"])
#⇒ {"556c53987eb55c82ffb6925f9f56eae5de01c119\n", 0}
git_sha
#⇒ "556c5398"
无论您需要的只是让送货愉快,您都可以使用 delivery config 来达到这个目的。只需将以下行放入 .deliver/config
:
AUTO_VERSION=commit-count+git-revision+branch-unless-master
这是我用于最终构建为版本化生产 RPM 的应用程序的方法。当针对干净标签构建时,版本是标签名称。否则,该版本包括短提交哈希和自上一个标记以来的提交计数。
它还支持通过在项目的根目录中包含一个 VERSION 文件来覆盖自动版本控制。
# mix.exs
defmodule MyApp.Mixfile do
use Mix.Project
@default_version "v1.0.0-default"
def project do
[
app: :my_app,
version: version(),
elixir: "~> 1.6",
# ...
]
end
# ...
defp version do
# Build the version number from Git.
# It will be something like 1.0.0-beta1 when built against a tag, and
# 1.0.0-beta1+18.ga9f2f1ee when built against something after a tag.
with {:ok, string} <- get_version(),
[_, version, commit] <- Regex.run(~r/(v[\d\.]+(?:\-[a-zA-Z]+\d*)?)(.*)/, String.trim(string)) do
String.replace(version, ~r/^v/, "") <> (commit |> String.replace(~r/^-/, "+") |> String.replace("-", "."))
else
other ->
IO.puts("Could not get version. error: #{other}")
@default_version
end
end
defp get_version do
case File.read("VERSION") do
{:error, _} ->
case System.cmd("git", ["describe"]) do
{string, 0} -> {:ok, string}
{error, errno} -> {:error, "Could not get version. errno: #{inspect errno}, error: #{inspect error}"}
end
ok -> ok
end
end
end
我们使用的解决方案是
defmodule EvercamMedia.Mixfile do
use Mix.Project
def project do
[app: :evercam_media,
version: "1.0.#{DateTime.to_unix(DateTime.utc_now())}",
elixir: "~> 1.11.1",
elixirc_paths: elixirc_paths(Mix.env),
build_embedded: Mix.env == :prod,
这个,它工作得很好。
解决方案,我已经接受了,当你部署分支然后主控时,热升级将不起作用。
此外,使用 Ansible 进行部署时最重要的部分是触摸您的 mix.exs
以便它可以编译并获取新版本。
我已经写了一篇关于它的文章Hot Code Upgrade
我正在使用 distillery 为 phoenix 应用程序进行热代码升级。我用它来创建应用程序的版本。
def project do
{result, _exit_code} = System.cmd("git", ["rev-parse", "HEAD"])
git_sha = String.slice(result, 0, 7)
[app: :evercam_media,
version: "1.0.1-a#{git_sha}",
elixir: "~> 1.7",
elixirc_paths: elixirc_paths(Mix.env),
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
compilers: [:phoenix] ++ Mix.compilers,
aliases: aliases(),
deps: deps()]
end
这会创建版本,但该版本不适用于热代码升级并会弄乱 relup
文件。当我进行 1.0.1、1.0.2 和 1.0.3 之类的版本控制时。然后热代码部署工作正常。但是有什么办法可以让这个东西动态化吗?
我正在使用 distillery 部署到远程服务器。
更新:
我正在使用 distillery 进行部署,但自动版本无法正常工作,除非它们是 1.0.1 或 1.0.2 或 1.0.3。我试过下面的答案。以及 git describe --tags
也是如此。但酒厂只使用 2 个版本,然后每次使用过去的版本创建新版本。
git_sha
的问题是它没有排序。根据普通字母数字排序,下一个版本的编号被假定为大于前一个版本。 sha
情况并非如此。
您可以为此目的使用日期。例如
git log -1 --date=raw --format=%cd
#⇒ 1535467693 +0200 # seconds since epoch
现在让我们把它炼成:
{epoch, _} = System.cmd("git", ~w|log -1 --date=raw --format=%cd|)
[sec, tz] =
epoch
|> String.split(~r/\s+/, trim: true)
|> Enum.map(&String.to_integer/1)
#⇒ [1527769224, 200]
sec + tz * 36 # * 60 * 60 / 100
#⇒ 1527776424
上面的数字一直在增长。
旁注: 尽可能使用就地二进制模式匹配而不是 String.slice/3
:
{<<git_sha::binary-size(8), _rest::binary>>, _exit_code} =
System.cmd("git", ["rev-parse", "HEAD"])
#⇒ {"556c53987eb55c82ffb6925f9f56eae5de01c119\n", 0}
git_sha
#⇒ "556c5398"
无论您需要的只是让送货愉快,您都可以使用 delivery config 来达到这个目的。只需将以下行放入 .deliver/config
:
AUTO_VERSION=commit-count+git-revision+branch-unless-master
这是我用于最终构建为版本化生产 RPM 的应用程序的方法。当针对干净标签构建时,版本是标签名称。否则,该版本包括短提交哈希和自上一个标记以来的提交计数。
它还支持通过在项目的根目录中包含一个 VERSION 文件来覆盖自动版本控制。
# mix.exs
defmodule MyApp.Mixfile do
use Mix.Project
@default_version "v1.0.0-default"
def project do
[
app: :my_app,
version: version(),
elixir: "~> 1.6",
# ...
]
end
# ...
defp version do
# Build the version number from Git.
# It will be something like 1.0.0-beta1 when built against a tag, and
# 1.0.0-beta1+18.ga9f2f1ee when built against something after a tag.
with {:ok, string} <- get_version(),
[_, version, commit] <- Regex.run(~r/(v[\d\.]+(?:\-[a-zA-Z]+\d*)?)(.*)/, String.trim(string)) do
String.replace(version, ~r/^v/, "") <> (commit |> String.replace(~r/^-/, "+") |> String.replace("-", "."))
else
other ->
IO.puts("Could not get version. error: #{other}")
@default_version
end
end
defp get_version do
case File.read("VERSION") do
{:error, _} ->
case System.cmd("git", ["describe"]) do
{string, 0} -> {:ok, string}
{error, errno} -> {:error, "Could not get version. errno: #{inspect errno}, error: #{inspect error}"}
end
ok -> ok
end
end
end
我们使用的解决方案是
defmodule EvercamMedia.Mixfile do
use Mix.Project
def project do
[app: :evercam_media,
version: "1.0.#{DateTime.to_unix(DateTime.utc_now())}",
elixir: "~> 1.11.1",
elixirc_paths: elixirc_paths(Mix.env),
build_embedded: Mix.env == :prod,
这个,它工作得很好。
解决方案,我已经接受了,当你部署分支然后主控时,热升级将不起作用。
此外,使用 Ansible 进行部署时最重要的部分是触摸您的 mix.exs
以便它可以编译并获取新版本。
我已经写了一篇关于它的文章Hot Code Upgrade