Last active
July 21, 2023 17:23
-
-
Save aiwaiwa/ac15f5d1019dfebfa342fafad4a9cb3d to your computer and use it in GitHub Desktop.
Compare Phoenix Versions with extra custom steps like mix phx.gen.live Accounts User users name:string
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Compare Phoenix releases with additional custom setup to enhance comparison. | |
# | |
# Usage: | |
# elixir <this_script_name.exs> 1.7.2 | |
# (downloads 1.7.2 and compares with the closest previously downloaded version if available) | |
# | |
# elixir <this_script_name.exs> 1.7.2 1.7.7 | |
# (downloads both versions and compares) | |
# | |
# To recreate the folders, pass --force. | |
# | |
# The script grabs a Phoenix version and places generated project | |
# under `phoenix/<version>/<project>` where <project> is a configurable name. | |
# It attempts to call a diff GUI, if there's a previous version found in `phoenix` | |
# or command line provides two version numbers to compare. | |
# | |
# To add set steps, modify PhoenixCompareConfig | |
# to bring in your diff tool and add additional | |
# steps after blank project creation. | |
# | |
# TODO: Work in temporary folders until end, then move to destination. | |
# TODO: Sanitize temporary folders. | |
# TODO: Patch migration file names to be precisely matching. | |
# | |
defmodule PhoenixCompareConfig do | |
@doc "project name to pass to mix phx.new <project_name>" | |
def project_name, do: "project" | |
@doc "Additional steps to execute on a new phoenix project. Caller expects :ok on success." | |
def steps(into_path, project_name) do | |
{_, 0} = | |
cmd(["mix phx.gen.live Accounts User users name:string"], | |
cd: Path.join(into_path, project_name), | |
stderr_to_stdout: true | |
) | |
# {_, 0} = | |
# cmd(["mix phx.gen.live Accounts CashFlow cash_flows user:references:users amount:integer currency:string"], | |
# cd: Path.join(into_path, project_name), | |
# stderr_to_stdout: true | |
# ) | |
:ok | |
end | |
def exec_maybe_diff(%Version{} = previous, %Version{} = current) do | |
case previous do | |
nil -> | |
IO.puts( | |
"Skipping diff: no version < #{current} is found processed. Request it with this script and try again." | |
) | |
_ -> | |
IO.puts("#{previous} <-> #{current}") | |
case :os.type() do | |
{:win32, _} -> | |
Task.async(fn -> | |
cmd([ | |
~S<C:\Program Files (x86)\WinMerge\WinMergeU.exe>, | |
"/r", | |
# Titles | |
"/dl", | |
"#{previous}", | |
"/dr", | |
"#{current}", | |
# Read only | |
"/wl", | |
"/wr", | |
Path.join("phoenix", ["#{previous}", "/", project_name()]), | |
Path.join("phoenix", ["#{current}", "/", project_name()]) | |
]) | |
end) | |
_ -> | |
IO.puts("Skipping diff: not implemented for #{:os.type()} yet. Please PR!") | |
end | |
end | |
end | |
def cmd([_ | _] = what, options \\ []) do | |
{cmd, args, options} = | |
case :os.type() do | |
{:win32, _} -> | |
{"cmd", ["/c"] ++ what, options} | |
# _os_name | |
# ------------ | |
# :darwin | |
# ... | |
{:unix, _os_name} -> | |
[head | tail] = what | |
{head, tail, options} | |
end | |
# stream = IO.binstream(:standard_io, :line) | |
stream = IO.binstream(:stdio, :line) | |
options = Keyword.put_new(options, :into, stream) | |
System.cmd(cmd, args, options) | |
end | |
end | |
defmodule Execute do | |
import PhoenixCompareConfig | |
def already_exists_fail(version, is_force) do | |
path = phoenix_version_path(version) | |
case File.stat(path) do | |
{:ok, _stat} -> | |
case is_force do | |
true -> | |
case File.rm_rf(path) do | |
{:ok, _} -> :ok | |
{:error, reason, file} -> {:error, "#{file} failed to delete due to #{reason}"} | |
end | |
false -> | |
{:error, "#{path} already exists. Add --force to recreate"} | |
end | |
{:error, _reason} -> | |
:ok | |
end | |
end | |
def get_phx_new(%Version{} = version) do | |
{_, 0} = | |
cmd(["mix", "archive.install", "--force", "hex", "phx_new", "#{Version.to_string(version)}"]) | |
:ok | |
end | |
def recreate_path(%Version{} = version) do | |
path = phoenix_version_path(version) | |
File.rm_rf!(path) | |
:ok = File.mkdir_p(path) | |
{:ok, path} | |
end | |
def initiate_phx_new(into_path, project_name) do | |
# mix phx.new <project_name> | |
{_, 0} = | |
cmd(["mix phx.new #{project_name} --no-install"], | |
cd: into_path, | |
stderr_to_stdout: true | |
) | |
{_, 0} = | |
cmd(["mix deps.get"], | |
cd: Path.join(into_path, project_name), | |
stderr_to_stdout: true | |
) | |
steps(into_path, project_name) | |
end | |
def arv_all_like_versions do | |
System.argv() | |
|> Enum.map(fn a -> | |
case Version.parse(a) do | |
{:ok, version} -> version | |
_ -> nil | |
end | |
end) | |
|> Enum.filter(fn v -> v != nil end) | |
end | |
def argv_has_force do | |
Enum.find_index(System.argv(), fn v -> v == "--force" end) != nil | |
end | |
def phoenix_version_path(%Version{} = version) do | |
# version = Version.to_string(version) | |
Path.join("phoenix", "#{version}") | |
end | |
def build(src) do | |
{_, 0} = cmd(["npm run build"], cd: src) | |
:ok | |
end | |
def available_prev_version(%Version{} = version) do | |
{:ok, versions} = File.ls("phoenix") | |
sorted = Enum.sort(versions, fn a, b -> Version.compare(a, b) == :lt end) | |
idx = Enum.find_index(sorted, fn v -> v == Version.to_string(version) end) | |
cond do | |
idx > 0 -> Version.parse!(Enum.at(sorted, idx - 1)) | |
true -> nil | |
end | |
end | |
def maybe_diff(previous, current), do: PhoenixCompareConfig.exec_maybe_diff(previous, current) | |
def get_version(version, is_force) do | |
case Execute.already_exists_fail(version, is_force) do | |
:ok -> | |
:ok = Execute.get_phx_new(version) | |
{:ok, path} = Execute.recreate_path(version) | |
:ok = Execute.initiate_phx_new(path, PhoenixCompareConfig.project_name()) | |
{:error, reason} -> | |
IO.puts(reason) | |
end | |
end | |
def main() do | |
is_force = Execute.argv_has_force() | |
versions = Execute.arv_all_like_versions() | |
case versions do | |
[a, b | _] -> | |
get_version(a, is_force) | |
get_version(b, is_force) | |
Execute.maybe_diff(a, b) | |
[a] -> | |
get_version(a, is_force) | |
b = Execute.available_prev_version(a) | |
Execute.maybe_diff(a, b) | |
_ -> exit("At least one Phoenix version is expected") | |
end | |
end | |
end | |
Execute.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment